次にhttpdタスクを見てみましょう。
リスト10は、httpdタスク(httpd.c)の先頭部分にある文字列の定義です。見れば分かるように、送信するHTML文字列をそのまま文字列データ(つまり、charの配列)としてプログラム中に格納しています。
KOZOSはファイルシステムを持たないため、HTMLデータを文字列の“ベタデータ”としてプログラム中に直接保持しているわけです。
static char header[] = "HTTP/1.0 200 OK\r\n" /*"Date: Sat, 23 Oct 2010 12:00:00 GMT\r\n"*/ "Server: KOZOS-httpd/1.0\r\n" "Content-Type: text/html\r\n" "Content-Length: #####\r\n" "\r\n"; static char top_document[] = "<html>\n" "<head>\n" "<title>This is KOZOS!</title>\n" ……(中略)…… "<h1>HTTP server on KOZOS (#####)</h1>\n" "<p><a href=\"about.html\">KOZOSとは?</a>\n" "<p><a href=\"kozos.html\">KOZOSの現状</a>\n" ……(中略)…… static char about_document[] = "<html>\n" "<head>\n" "<title>KOZOSとは?</title>\n" ……(中略)…… "<center><h1>KOZOSとは?(#####)</h1></center>\n" "<p>KOZOSは坂井弘亮が作成している、学習向けの組み込みOSです。主に秋月電子のH8/3069Fマイコンボードで動作し、組み込みOSの自作・動作などの学習ができます。\n" "<p>以下の点で、個人での学習用に向いています。\n" ……(中略)…… static char kozos_document[] = "<html>\n" "<head>\n" "<title>KOZOSの現状</title>\n" ……(中略)…… "<center><h1>KOZOSの現状(#####)</h1></center>\n" "<p>KOZOSはKOZOSプロジェクトにより開発が進められています(まあ坂井1人でやっているのですが)。\n" "<p>以下が既に実現されています。\n" ……(中略)…… static char makeos_document[] = "<html>\n" "<head>\n" "<title>組み込みOSを作ってみませんか?</title>\n" ……(中略)…… "<center><h1>組み込みOSを作ってみませんか?(#####)</h1></center>\n" ……(中略)……
リスト10 HTML文字列をベタデータとして格納する(httpd.c) |
以下、リスト11の配列documents[]は、これらの文字列データへのポインタの配列と、それに対応するファイル名のテーブルです。HTTPのGETメソッドでファイル名を要求されたら、このテーブルと照らし合わせて、対応するHTMLデータを返してやればいいわけです。
static struct documents { char *counterp; char *filename; char *document; } documents[] = { { NULL, "/index.html", top_document }, { NULL, "/about.html", about_document }, { NULL, "/kozos.html", kozos_document }, { NULL, "/makeos.html", makeos_document }, { NULL, NULL, unknown_document } };
リスト11 ファイル名とHTMLデータの対応(httpd.c) |
リスト12は、httpdタスクの初期化処理とメインループです。
static void send_accept() { ……(中略)…… buf->cmd = TCP_CMD_ACCEPT; ……(中略)…… buf->option.tcp.accept.port = 80; kz_send(MSGBOX_ID_TCPPROC, 0, (char *)buf); } int httpd_main(int argc, char *argv[]) { ……(中略)…… send_accept(); ……(中略)…… while (1) { kz_recv(MSGBOX_ID_HTTPD, NULL, (char **)&buf); switch (buf->cmd) { ……(中略)…… case TCP_CMD_RECV: ……(中略)…… ret = parse(number, buffer); ……(中略)…… }
リスト12 httpdタスクのメインループ(httpd.c) |
httpd_main()の最初で、send_accept()を呼び出し、tcpタスクに対して接続待ち受けの依頼を行います。さらに、send_accept()では「MSGBOX_ID_TCPPROC」で待ち受けをします。これにより、実際にデータを受信した際、kz_recv()で受信データを受け取ることになります。受信したデータは、parse()によって解析を行います。
リスト13が、parse()の実装となります。
static int parse(int number, char *str) { ……(中略)…… if (strncmp(str, "GET", 3)) return 0; for (p = str + 3; *p == ' '; p++) ; filename = p; ……(中略)…… for (docs = documents; docs->filename; docs++) if (!strcmp(filename, docs->filename)) break; ……(中略)…… send_string(number, header); send_string(number, docs->document); ……(中略)…… }
リスト13 受信データの解析処理(httpd.c) |
parse()では、GETメソッドの行からファイル名を抽出し、リスト11の配列documents[]からファイル名を検索して、対応するHTMLデータを取得します。さらに、send_string()により、HTTPヘッダとHTMLのメッセージを送信します。
リスト14が、send_string()の実装です。
static void send_write(int number, int size, char *data) { ……(中略)…… buf->cmd = TCP_CMD_SEND; ……(中略)…… kz_send(MSGBOX_ID_TCPPROC, 0, (char *)buf); } static void send_string(int number, char *str) { ……(中略)…… send_write(number, size, str); ……(中略)…… }
リスト14 HTTPの応答の送信(httpd.c) |
send_string()からはsend_write()を呼び出します。send_write()では、tcpタスクに対してデータをメッセージ送信することで送信依頼をします。後は、tcpタスクが送信処理を適切に行ってくれることになります。
Copyright © ITmedia, Inc. All Rights Reserved.