イギリスの政府通信本部(GCHQ)が現在採用活動の一環として、「Can you crack it?」と題して暗号解読クイズページを公開しています。
イギリス人であればこれをクリアするとエントリーフォームからエントリーできるみたいです。
で、先日大学の友達と相談しながらクリアしました。
実はこれ、表示されてる問題をクリアしたと思ったらstage 2 of 3が出て来ます(笑)。
面白かったので、解答までの流れをブログに書きたいのですが、期日まであと1日ちょっとあるので、その後にします。
イギリスの政府通信本部(GCHQ)が現在採用活動の一環として、「Can you crack it?」と題して暗号解読クイズページを公開しています。
イギリス人であればこれをクリアするとエントリーフォームからエントリーできるみたいです。
で、先日大学の友達と相談しながらクリアしました。
実はこれ、表示されてる問題をクリアしたと思ったらstage 2 of 3が出て来ます(笑)。
面白かったので、解答までの流れをブログに書きたいのですが、期日まであと1日ちょっとあるので、その後にします。
前回の投稿と打って変わって組込系の話題を。
最近STM32でCANとか使っているのですが、時々送信に失敗してしまうという問題がありました。
たまになので問題ないのですが、気になったので調べてみるとSTMicroが用意しているSTM32F10x standard peripheral libraryのバグでした。バージョンは04/16/2010 のV3.3.0と古いやつですが。
具体的に言うと、現在送信しようとしているメッセージの状態を確認する関数
CAN_TransmitStatus にあります。
ここでは CANxのTSRレジスタのTSS_RQCP0、TSR_TXOK0、およびTSR_TME0ビットの値を見て、
CANTXPENDING(送信中)、CANTXFAILED(失敗)、CANTXOK(成功)を返しています。
が、こんな風にレジスタにアクセスするようなコードになってます。
switch (TransmitMailbox)
{
case (0): state |= (uint8_t)((CANx->TSR & TSR_RQCP0) << 2);
state |= (uint8_t)((CANx->TSR & TSR_TXOK0) >> 0);
state |= (uint8_t)((CANx->TSR & TSR_TME0) >> 26);
break;
case (1): state |= (uint8_t)((CANx->TSR & TSR_RQCP1) >> 6);
state |= (uint8_t)((CANx->TSR & TSR_TXOK1) >> 8);
state |= (uint8_t)((CANx->TSR & TSR_TME1) >> 27);
break;
case (2): state |= (uint8_t)((CANx->TSR & TSR_RQCP2) >> 14);
state |= (uint8_t)((CANx->TSR & TSR_TXOK2) >> 16);
state |= (uint8_t)((CANx->TSR & TSR_TME2) >> 28);
break;
default:
state = CANTXFAILED;
break;
}
これでは、レジスタに3回アクセスしてしまっており、アクセスとアクセスの間でレジスタの値が変わってしまうと変なstatusになってしまいます。その結果 default で CANTXFAILED がセットされてしまうというのが送信失敗の原因です(実際にはこの瞬間に成功しているが、失敗したと判断してしまう)。
最も修正量の少ない解決策は簡単で、CANx->TSRの値を一旦変数に入れてやればいいのです。
uint32_t _tsr = CANx->TSR;
switch (TransmitMailbox)
{
case (0): state |= (uint8_t)((_tsr & TSR_RQCP0) << 2);
state |= (uint8_t)((_tsr & TSR_TXOK0) >> 0);
state |= (uint8_t)((_tsr & TSR_TME0) >> 26);
break;
case (1): state |= (uint8_t)((_tsr & TSR_RQCP1) >> 6);
state |= (uint8_t)((_tsr & TSR_TXOK1) >> 8);
state |= (uint8_t)((_tsr & TSR_TME1) >> 27);
break;
case (2): state |= (uint8_t)((_tsr & TSR_RQCP2) >> 14);
state |= (uint8_t)((_tsr & TSR_TXOK2) >> 16);
state |= (uint8_t)((_tsr & TSR_TME2) >> 28);
break;
default:
state = CANTXFAILED;
break;
}
こんな風に。
で、最新のV3.5.0ではちゃんと修正されてました。
switch (TransmitMailbox)
{
case (CAN_TXMAILBOX_0):
state = CANx->TSR & (CAN_TSR_RQCP0 | CAN_TSR_TXOK0 | CAN_TSR_TME0);
break;
case (CAN_TXMAILBOX_1):
state = CANx->TSR & (CAN_TSR_RQCP1 | CAN_TSR_TXOK1 | CAN_TSR_TME1);
break;
case (CAN_TXMAILBOX_2):
state = CANx->TSR & (CAN_TSR_RQCP2 | CAN_TSR_TXOK2 | CAN_TSR_TME2);
break;
default:
state = CAN_TxStatus_Failed;
break;
}
一度でアクセスするようになってます。でも返値変わってて、最新版に置き換えるのは大変そう…
今回はSSL(https)を使えるようにするような設定をnginxにしてみようと思います。
本来はSECOMやVeriSign等に有料で証明してもらうのですが、今回は以前にも紹介したCACertを載せときます。
ということで、証明書の取得は省略します。とりあえず、サーバーの秘密鍵 server.key と サーバーの証明書 server.cer が手に入った事にします。
nginxでの設定は簡単で、既存の設定をコピーして、80番ではなく443番に変更し、SSLを有効にしてサーバーの鍵・証明書のファイルを指定してあげるだけです。
ちょっとその部分だけ書いてみます。
server {
listen 443 default_server ssl;
server_name _;
ssl_certificate /keys/server.cer;
ssl_certificate_key /keys/server.key;
location / {
この辺は適当に
}
}
リバースプロキシとしてnginxとして使っている場合も同様です。
ドメイン名を複数つかってバーチャルホストを使っている場合もあると思います。SSLではアクセスされたサーバー名がわかる前に証明書を渡さなければならないので、名前ベースのバーチャルホストでSSLは利用できませんでした。
が、SNI(Server Name Indication)というプロトコル拡張ができたので、名前ベースのバーチャルホストでも可能になりました。(ブラウザによっては対応してません)
設定は簡単で、httpと同じくserver_nameを設定するだけです。
リバースプロキシとして使っている場合は、証明書を変えるために、バーチャルホストの数だけServerディレクティブを作ってあげてください。
(多分)一般的なWebサーバーであるApacheは複雑な設定も可能で便利なのですが、その分重いのです。
どう重いのかというと、Apacheは一つのプロセスが一つのHTTPリクエストを同期処理で裁いてるのでその間は他の処理をしません。なので、同時アクセス数が増えるとApacheはプロセスをどんどん生成します。(あるいは後からきたリクエストを待たせる)
なので、アクセス数が増えると急激にパフォーマンスが落ちるという問題を抱えてます。(ほかにもプロセスIDが足りなくなってどんなにリソースがあっても最大プロセスIDで制限されてしまう)
で、最近話題のハイパフォーマンスWebサーバーがnginx(えんじんえっくす)です。
nginxは一つのプロセスで複数のリクエストを非同期で同時に処理します。なので、アクセス数が増えてもパフォーマンスが落ちにくいという特性があります。特に静的ファイルの場合は処理のほとんどがI/O待ちなので効果が大きいです。
そこで、PHPとかSVNとか設定がめんどくさいものはApacheに任せておいて、静的なファイルだけをnginxに処理させてみると、Apacheへのリクエスト数は激減するはずです。
例えば、このブログのトップページの場合PHPで生成されるHTMLが一個にたいして、CSSや画像等の静的ファイルが20個近くあります。単純計算で21個のリクエストのうち1個だけがApacheで処理されるのでApacheへのリクエストは約95%削減されます。
では設定してみましょう。OSはUbuntu Server 10.04(64bit)です。Apacheは既にインストール済みで運用されているとします。設定後はnginxがポート80で待ち受けて、Apacheはポート8080で待ち受けるということにします。
(記事の最後でキャッシュファイルをRAMに置くというのもやってみます)
さっきの投稿でWordPressが遅い事を書きました。で、先輩のさくらのVPS(nginx+fastcgi)では速いってことも書きました。
ということで、僕も借りてるさくらのVPSで一からセットアップして実験してみました。OSはデフォルトではなくUbuntu 10.04が入ってます。
今回検証したのは、WebサーバーはApache/2.2.14とnginx/1.0.9、RDBMはMySQL(Ver 14.14 Distrib 5.1.41, for debian-linux-gnu (x86_64) using readline 6.1)とPostgreSQL/8.4.9です。なので、合計4通りですね。
Apacheではmod_phpで、nginxでは後ろでspawn-fcgiが動いてます。
で、試してみた結果です。今回検証したいのは静的ファイルではなくPHPの出力なので、画像とかCSSがブラウザでキャッシュされてたりするのは気にしないでください。
平均もとってない1回こっきりのアクセスの結果なので互いの比較はそんなに意味がないです。
が、どれもレイテンシが数百ミリ秒あります。これは何回試しても同じでした。
あれ?…
先輩のVPSと同じ環境のはずなのになんでこんなに違うの?