title_parttitle_parttitle_part
静岡県浜松市であれこれソフトを開発している A.K.I Software のブログです。日々の開発日記やサーバー・セキュリティ関連の話題なども掲載。
<< 2024/04 >>123456789101112131415161718192021222324252627282930
《《《 ネットワーク機器の購入は Amazon で! 》》》
Powered by BLOM メールサーバーの開発を始めて20年
小さくも大きくも閉じたりもしません
24/02/07 21:46 / PMailServer2

ふとマニュアルを確認していた所、PMailServer というメールサーバーの開発を始めてから 20年経過したようです。

開発している本人も、ここまで開発を続けるとは思ってもいませんでしたね。

折角なので、つらつらと、振り返ってみます。

〜〜 ネーミングについて 〜〜

FAQ の末尾にも少し書いていますが、元々 GMail Server という名前で開発をしていました。
実行ファイル名は gm.exe
サービスアプリでは無く常駐型ソフトでした。

FAQ には「Gには意味がない」と書いていますが、当時遊んでいた某MMOゲームで、ゲームマスター(Game Master)を略して GM と呼んでいたので、なんとなく gm.exe と名前を付けて、そこから GMail Server と文字ったのでした。

で、一旦 HDD クラッシュにて全ソース紛失ということで、最初から構築しなおした時に、gm.exe じゃなぁ・・・と名称を変更することに。
G を P に変えて、PMailServer にしようということなりました。

で、この P ですが、FAQ に同じく意味がないと書いていますが、実のところゲーム内で利用しているキャラクター名の頭文字が P なので、P にしました。
なんという安易な名前付け。

ほんとソフトウェアのネーミングって(私にとっては)難しいんですよ。未だに新規プロジェクトを作成する時に名前に悩みますので。

もう10年以上前になりますが、地元企業からの依頼で ECシステムを開発した際に管理者だけが使える専用ツールを作成したのですが、ファイル名が godhand.exe
幸いなことに、現在も現役で稼働しているシステムなのですが、電話などで出るんですよ、ツールの名前が。
「あー、神の手を使ってレコードを削除していいですか?」とか。

未だに止めてください。恥ずかしくて死んでしまいます。と思っていますが、先方の中ではもう名前が固定されていますので、今更ファイル名を変えても多分、呼び名は変わらないでしょう・・・

〜〜 開発のきっかけ 〜〜

当時、国産のメールサーバーは殆ど無く、小規模向けのサーバーか、Microsoft Exchange Server を使うかという状況でした。(もちろん他にもあったとは思いますが、当時知っていたメールサーバーはこれくらいでした)
MS Exchange Server は高額でしたので、当然購入できず。
他のメールサーバーもユーザー数によってライセンスが変わる。という条件でしたので、うーん、後で追加ライセンスとかしっくりこないな。と言うことで

「なら、作るか。」

本当にこれがきっかけです。
最初フリー版から作ったのも、当時 Windows でサーバーを構築?コストかかりすぎじゃない?メールやウェブサーバー運用は UNIX系だよね。タダだし。的な面がありましたので、その影響もあったと思います。
また製品版にするつもりも当初はありませんでした。ある程度作って「売れるんじゃない?」と思ったのがきっかけです。

はっきり言うと、UNIX系で無料のサーバーがあるのに Windows でサーバーを作っても商業ベースには乗らないだろうという思いもありました。
まぁ、今でも PMailServer2 だけでビジネスが成り立つか?と言えば、成り立っていませんが。

開発当時は、特に受注開発のソフトなどの依頼は余り無く、時間だけはありましたので、RFCなどを読みながらプロトコルを実装していきました。

唯一の例外が DNS クライアント機能。
当時は今以上に英語ができなかったので(別に今は英語が得意という訳ではありません)基本的に翻訳ソフト便りでRFCを呼んでいたのですが、DNS だけ今ひとつピンと来ない。

そんな中、本屋で TCP/IP 関連の書籍を見ていたところ、こんな本がありました。

photo
今は絶版になっていますが、CQ出版の OPEN DESIGN No.3

photo
この中に4ページだけ DNS のパケット構造が書かれています。

実は RFC + この4ページを頼りに DNS クライアントを完成させました。(あとはバイナリエディタでパケットを眺めて手動でデコードしたりしてトライアンドゴーです)
特にパケットの圧縮方法が書かれていたのが大きかった記憶があります。
RFC 見ても全然わからなかったので。
(その後、逆をすればいいだろうと言うことで DNS サーバーも完成させています)

〜〜 専用Webmail 〜〜

Webmail に関しては、PMailServer よりも先に、NTBBS などの掲示板ソフトを作っていました。
今もサポート掲示板で使っている CGI です。

SMTPやPOP3は当然理解しているので、CGI で実装すれば良いと考えましたが、直接メールボックスを参照すれば早いよね。ということで、専用のクライアントにすることに決定。

今は JavaScript も活用していますが、当時は JavaScriptが余り信用できず、かなり強引なHTML構造になっています。実の所、これが今でも足かせになっていたりします。
ただ作り直すには余りにも巨大なので、二の足を踏む状況にもなっています。

現在の PMailServer2 をフルコンパイルした時のコード行数が約 20万行ですが Webmail は、約17万行になっています。
HTMLが多いとは言え、本体並みの手間が掛かっています。

一般的に利用されている Outlook や Thunderbird などのメールクライアントはテスト以外では 10年以上利用していませんので、自分が欲しいから改良を続けているという感じですね。

〜〜 IMAP4対応 〜〜

なにかのネットニュースで、これからはスマホの時代だ。そうなると POP3 では無く今後は IMAP4 が主流になるだろう。という記事を読んだことがきっかけだったと思います。

単純なので「じゃぁ、IMAP4 に対応しよう」ということで、IMAP4 の実装を開始しました。
私はスマホに変えたのも結構後でして、当時はガラケーのみで Webmail がガラケーに対応すればいいのでは?という考えでしたが、POP3 が廃れていく(結局は現在も併用されていると思いますが)ならば、と思った訳です。

正確な期間は覚えていませんが、ソースコードを見る限り、初期の実装は3ヶ月くらいかかったと思います。(うろ覚えです。)

実装を始めてみて、兎に角実装をしなければならないコマンドが多すぎ。
そのコマンドも、思いつきで決めたんじゃないか?というコマンドが多すぎで、面倒くさい面倒くさいと思いながら実装していた覚えがあります。
(しかしながらプログラマの性というのでしょうか。面倒くさいと言いながらも徐々に動いてくのを見ると楽しくもなっていました)

詳細は知りませんが、IMAP4 は RDB と連携して動かすことを前提としている感じがありまして特に検索に関しては、日付などが 01-Jan-2024 のような書式になっています。
2024-01-01 でいいじゃないか固定長だし処理もしやすい、変換テーブルも不要なのにと思っていました。(今でも思っています)

BODYSTRUCTURE というメールの構造体を取得するコマンドがありますが、C言語のような構造体で返す必要があるので、これも面倒くさいな、なんでこんな処理系になっているんだろ?と思ったものです。

今思うと、当時無料の RDB があり、各構造体を処理するようなパーサ(Parser ツリー構造でデータの構造体を処理する処理系ライブラリやプログラム)があるので、それらを使えば簡単に実装できるでしょうと言う意図があったと思いますが、なんせ PMailServer 当時から外部のライブラリは一切利用しないで開発をしていましたので(正確にはコンパイラのランタイムが内蔵されており、Windows OS の API は利用していますので、一切という訳ではありませんが、基本的に全ての処理のソースコードは私自身で作成するようにしています)

photo
IMAP4 パーサのソースコードの一部。
開発は Delphi(Object Pascalの派生。既に Delphi という一つの言語ですね)
C や C++ にはオープンソースなども含めて豊富なライブラリがありますが、当時の Delphi には探せばあったかもしれませんが、私が知る限り無かったので全て自分で作る癖がついています。

余談ですが、私が Delphi において、唯一外部のライブラリに頼ったのは DelphiX という Delphi で DirectX を処理するライブラリと、OpenGL ライブラリですね。
DirectX は DirectX9 の頃に分厚いリファレンスを購入しましたが、無理だーと諦めました。仕事で使う訳でもなかったので。
OpenGL については、実は PC88 で販売されていた某ゲームを Windows に移植するという企画がありまして、偶然にもその企画の関係者(デザイナー)が知り合いでして「遊びに来なよ」と誘われて、一路東京まで。
私も知っているゲームだったこともあり「こんな感じだったら面白いな」というノリで「企画側には黙って、勝手に開発に着手」したりしました。(のちにデザイナーと結託して、ある程度動く所まで出来た時点で、企画が頓挫してしまい、連絡不通となってしまいました)
当ブログの「ゲーム開発」というカテゴリに当時 OpenGL を作った記事が少し残っています。

〜〜 SSL/TLS に対応と PMailServer2 へのメジャーバージョンアップ 〜〜

大幅に話がずれてしまいましたが、SMTP/POP3/IMAP4 と対応して対応することが余り無くなってきた事と、SSL通信が必要になってきましたので、これらに対応することにしました。
特に SSL/TLS通信対応については、全プロトコルに影響するので、この際メジャーバージョンアップも行うことにしました。
既に PMailServer の開発から、7,8年経過していたのと、1.xx の後半に差し掛かっていたことと、その前に IMAP4対応版と銘打って別エディションをリリースしていたのですが、これだけ長期間無償でバージョンアップをしていたので、そろそろいいんじゃない?という感じもありました。
販売戦略的要素は皆無です。

SSL/TLS 通信に関しては、本当に初期の初期は OpenSSL を利用していましたが、外部のDLLを使うとなるとソフトと DLL の整合性を今後も考慮しなければならないと考え破棄して、自前で SSL通信を試みましたが無理無理だったので、なにか方法が無いかと探していた所、Windows の中に Cryptographic API(CAPI)という暗号化関連の API が実装されていることを知り、これを利用することにしました。
しかし、この CAPI 当時日本語化された資料が余り無く、あっても Win32 API の一部として紹介されているだけでしたので、MSDN を見ながら1つづつ API のラッパー(内部処理をまとめて、外部からもっと簡単に使えるようにライブラリ化すること。例えばハンドシェイクをする箇所があった場合、外部から Handshake() という関数を呼ぶだけで自動で処理するような感じです)を実装。

いきなり TCP/IP 通信に組み込むことは出来なかったので、最初は「渡した文字列を暗号化してデータを取得。取得したデータを復号化する」辺りからコツコツと進めていました。

そんなことをしている間に、CAPI だけでは制御ができない箇所も出てきたので通信内容をパケットキャプチャして、バイナリエディタで眺めながら、SSL/TLS のパケットも解析するようにしました。

photo
SSL/TLSパケットの CLIENT_HELO を確認している箇所の実際のコード。
今ではバイナリエディタで見れば SSL/TLS 通信のパケットを直接読めるくらいにはなっています(笑)

暗号化・復号化が出来た時点でこれを TCP/IP 通信に組み込んでいきます。
今ではラッパーしているので、どんなプロトコルでも SSL/TLS通信ができるようになっていますが、ラッパー化これも結構苦労しました。

ただこれだけではバージョンアップの費用が高く感じたので IPv6 にも対応。(この為 Windows 2000 が非対応になりました)
この辺りでメールサーバーとしての基本機能は殆ど実装していましたので、PMailServer2 にメジャーバージョンアップを実施しました。

〜〜 非同期通信と 64bit化 〜〜

実は PMailServer2 にメジャーバージョンアップをする際に、同期通信から非同期通信に変更をしていました。
現在の PMailServer2 は、各接続単位で1スレッド使い、スレッド内は同期通信で処理を行っています。
これが同時接続数のボトルネックにもなっていました。

6,7割完成した時に「64bit化すれば、別にスレッド数の上限も増えるし、非同期にしなくてもいいんじゃないか?」と考えて、このコードは破棄。
今度は 64bit化の為にマイグレーション(Delphi で 64bit化する為には、Delphi2007 よりも後のバージョンにする必要がありました)が必要になったのですが・・・このマイグレーションがこれまでのコードと非常に相性が悪かったのです。

Delphiに触ったことがある方はご存知ですが、改めてこのマイグレーションで一番ネックになったのは、文字列の扱いです。
正確には、Delphi のデフォルトの文字列が ANSI型文字列から Unicode型文字列に「デフォルトの型が変わる」という劇的な変更があり、またサロゲートペア処理が加わりました。

極端な例ですが、今まで byte型を使っていて、これは 8bit ですね。と処理系を書いていた所、この版からは byte型は 16bit になります。と同じくらい衝撃的な出来事でした。
今までは String = AnsiString だったのが String = UnicodeString になった訳です。
もちろんコードでは変数の型は String と書いています。
String を使っている所は全部チェックしなければなりません。

「嗚呼、String = AnsiString のままで、UString = UnicodeString みたいにしてくれれば良いのに」と心底思ったものです。

元々、私がアセンブラから Pascal(私は MS-DOS 時代にアセンブラから Turbo Pascal に移行して、そこから TP for Windows になり、Delphi に至っています)になった理由の一つとして、文字列の扱いが非常に簡単だったからです。

アセンブラで文字列比較はメモリコンペアをして一致したら・・・という処理になりますが、Pascal だとイコールで結ぶだけ。これには非常に感銘を受けて、一気に Pascal 使いに変貌したという経緯があります。

で、通信にもこの文字列を多用していた訳です。正確には通信バッファに文字列(String型)を利用していました。
ぶっちゃけると、サロゲートペアって通信と非常に相性が悪いです。
なぜならば文字列として通信する訳では無く、場合によっては 1byteづつデータが送られてくる訳でして、また次の 1byte が送られてくる保証がありません。
しかし通信バッファを利用する箇所は全体から見てそれ程大きくなかったので、通信部分のマイグレーションは達成できました。

次に来たのは、PMailServer2 のフィルタ関連です。
ここでもサロゲートペアが大きく影響します。
ただでさえ文字化けが出たりするのに、spam メールなどはきちんと文字コードを守ったりしないケースも多々あります。
意図的に文字化けを起こしているが、特定のメーラーではそれを修復して表示するので受信すると問題ないように見える。
しかしフィルタする場合は、この修復も混みでデコードをしないと、ユーザーさんから「こういう風に指定しているけど、フィルタされないです。文字列は一致しているように見えますがなんででしょうか?」となります。

PMailServer2 のフィルタは、MIME で指定されている文字コードを完全には信用しておらず(それが spam の手段なので)独自に文字コードを解析して、文字コードの判定などもしています。

ここで、文字列の基本形がサロゲートペアになると、余計なことするな。になります。
これについては余りにも処理する量が多すぎて(それでも6割位までは頑張りました)とうとう断念します。
DLL にして、フィルタ処理は本体から分離することも考えましたが、結局作業量は同じか、ちょっと簡単になる程度でしかありませんでした。

また仮にマイグレーションが完了したとしても何年も開発を続けていたフィルタ処理が「全て確実に動作するか」の確認作業が待っています。
対象は、なにをやってくるかわからない spam メールで綺麗なデータじゃありません。
これらの理由により 64bit化は一時断念することになりました。
(通信部分だけで言えば 64bit化は完了しているんですよ・・・フィルタ内蔵じゃなければとっくに 64bit版が出せています)

ちなみにサロゲートペアが面倒くさいと言っていますが、新規でアプリを作る場合は別に気にしていません。
むしろ Windows 自身が UTF-16 がデフォルトになっていますので、英語版などで動かしても文字化けしませんので楽です。

あくまでも「PMailServer2 と死ぬほど相性が悪かった」ということです。

〜〜 シングルプロセスとマルチプロセス 〜〜

64bit化も頓挫して、さてどうしようと考えました。
この頃、C10K 問題という問題がありました。
1台のサーバーに Client が 10,000台(10K)接続してきた場合、どう捌くか?という話です。

ハードウェア的(ソフト的にもできますが)に考えるとロードバランサなどで、複数のサーバーに接続を分散するのが手堅いとして、最初 PMailServer2 専用のロードバランサっぽいものを作ることにしました。

photo
当時作成していたコードです。ある程度出来上がっていましたが後述の理由により中止。
ただ、このコードを流用して 非公開ですが Proxy サーバーを作りましたので無駄ではありませんでした。
蛇足ですが TInetServer というオブジェクトがありますが、これ UNIX系の Inetd っぽい動作をする独自のコンポーネントです。
基本 Windows プログラマですが、時々 ANSI-C を使って UNIX系のコンソールアプリを作ることもあります。

昔、アセンブラから C言語に移行する方は多かったと思いますが、C言語には行かず Pascal に移行したのは、それ程インパクトがあったからです。
あと当時の草の根BBSで Turbo Pascal を使ったシステムも割りとありました。
私に Turbo Pascal を見せたのも当時通信していた草の根BBSのシスオペさんです。これでプログラマ人生が変わったと言っても過言では無いかもしれません。

処理としては単純で、例えば DMZ の外側にこのサーバーを稼働させておき、DMZ内にある複数のサーバーに負荷に応じて接続を中継するような仕組みです。

ただ、これにも問題がありました。
ロードバランサとなるサーバーが別途1台必要になります。
そういう規模にそういうコストがかかるのはしょうがないとすることもできますが、私は「なんかイヤ。PMailServer2 が安くても意味ないじゃん」と考えました。

どれもこれも駄目だと思っていた時、ふと「Apacheってどうやってんの?」と疑問に思い調べてみると、MPM方式という複数のプロセスを事前に立ち上げておき、それらで分散処理をするという仕組みでした。

そもそも、同時接続に制限があるのは Windows で「1プロセス」で制御できるスレッド数に限界がある(32bit / 64bit どちらにもあります。ただし 64bit は扱えるメモリ量が多いので、限界値が高いです)からです。
「サーバー全体」であれば、限界値はもっと高い訳です。

なるほど!と思い、マルチプロセス化に着手します。
親プロセスから子プロセスを起動して、親プロセスは接続のみを担当して、実際の処理は子プロセスに全て任せる。
任せたら、次の接続に対して待機だけします。
子プロセスは親プロセスから受け継いた接続に対してスレッドを生成して処理を行う。

ネタがわかれば後は早いと、親プロセスとしての PMailServer2 と子プロセスとしての PMailServer2 で内部で処理を分離して、分散処理が行えるようにしました。
(と書くのは簡単ですが、各プロセス間での通信が必要になったりして、相応に苦労はしています。特に IMAP4 が!)

シングルプロセスモードとマルチプロセスモードを実装して、Std / Pro 版でも利用できるようにします。
ここで差別化の為に、プロセス数の制限が無い更に上位の Enterprise版を用意しました。

元々 PMailServer2 は小規模向けのサーバーとして開発しており価格も押さえていました。
むしろ、ある程度の規模以上に耐えられない仕様なので、それで高額な価格設定は申し訳無いでしょう。という考えでした。
しかし、ある程度の規模にも耐えられるようになりましたので価格を上げてもいいかな?と思った訳です。
相変わらず販売戦略的要素は皆無です。

このマルチプロセス化は、ある意味 64bit化の必要性を失わせる理由にもなりました。
極論するとメールサーバーは、基本対話型のファイル処理ソフトです。
受信したデータを保存して、要望に応じて保存したファイルを送信するだけと言えば、それまでです。

元々メモリも大量に使う訳でも無く、処理速度も一定水準があれば事足ります。
IMAP4 は検索などがありますので話が違いますが、IMAP4 クライアントの挙動を見ていると、結局の所、POP3 と同じような挙動をしています。

根本的な所ですが、IMAP4 は元々、クライアント側にストレージが無くとも必要に応じて必要な部分だけを取得して処理をするというのが基本設計です。検索なども、その為に色々な引数があります。しかしPC版のIMAP4クライアントを見ていると、メール受信してローカルに保存して・・・という感じなので、言葉が悪いかもしれませんが、フォルダ構造が使える POP3 として使えるくらいだなと思っています。

以前 i4portable という IMAP4 クライアントを作成しましたが、これは純粋に IMAP4 の基本設計に従ってローカルにメールの内容などは保存せず、受信データをオンメモリで全て処理します。もちろん毎回受信しますので通信量は多いですが。

閑話休題

上記のような理由があり 64bit は本格的に中止になりました。

〜〜 そして現在 〜〜

ある程度、PMailServer2 の開発は落ち着いており、不具合の報告をいただいた場合の対処や、思いついた機能を実装するような更新頻度になっています。

もちろん、最適化などの処理でまだやることは沢山残っていますので、開発が終了することは無いのですが、旧PMailServer の頃のような頻度での更新は無いと思います。
(当時、ユーザーさんから週間PMailServer と呼ばれたことがあります。それくらい更新頻度が高かったです)

まぁ20年も1つのソフトを開発していれば、ネタ切れになってくるのも当然なのですが。
もしかしたら IMAP4rev2 とか POP4 とか出てくるかもしれませんしね。

そんな訳で、今後とも PMailServer2 をよろしくお願いします。

あ、最後にですが PMailServer3 になることはありますか?と聞かれることがありますが、とりあえず予定はありません。
またサブスクリプション形式になることもありません。

最初の開発のきっかけに反することになりますからね。

[更新日付:2024/02/10 00:56:28]
トラックバックを見る(0)
Log Link [https://akisoftware.com/cgi-bin/blom.exe?akisoft+sl+b2a05f9ecbea01e34b8aaf6ebad581b1e0b18da4]
TB Link [https://akisoftware.com/cgi-bin/blom.exe?akisoft+tb+b2a05f9ecbea01e34b8aaf6ebad581b1e0b18da4]

記事へのコメント

コメントはありません

名前
コメントキー
 
コメントする時はキーを正確に入力して下さい
コメント
アドレスを含んだコメントはできません
© 2008-10 A.K.I Software all rights reserved.