httpd on forth

姪っ子が実家に里帰りしてる。生まれて半年になる赤ちゃんが重くて腱鞘炎になって しまったので、実家にHELP信号を送ったらしい。そしたら、孫に甘い両親がWelcomeの replayをした。ネゴシエーション成立。麗しいですな。

そんな訳で、おいらの所にも顔見せ興行にくるよって連絡が有った。主役は赤ちゃんなんだ けど、えっと名前何だっけな? キラキラネームっぽいんで、思い 出すのに一苦労。

で、やって来ましたよ。赤ちゃんをいきなり、玄関口の廊下に置き、両親達はリビングへ。 ちょっと、随分な仕打ちじゃない? その子の母によると、生後半年ながら、もうほふく前進 が出来るとか。それを見せてくれるって。

ほんとにほふく前進して来ましたよ。途中で止まる事があり、思わずネジが切れたかなと 思うと、また動き出す。見てて飽きないねぇ。おじいちゃん、おばあちゃんにとっちゃ、最高の おもちゃだと思うぞ。

もう、お座りから掴まり立ちも出来る。掴まり立ちの時は、まだちょっと腰がふらふらする けど、あとちょっとすれば安定するだろう?

体重は8Kgあるそうな。成長が早いって言ってたけど、どうなの? 赤ちゃんの成長見比べを見ると、 随分とマセタ子のようだ。3頭身から4頭身になりかかってるしね。最後は、8頭身ぐらいに なるのかな。まだ、蒙古班は残ってるけど、そろそろ消えるのかな?

予防接種が大変みたい。自由接種のワクチンは1回数万円とか、それを何回かやるらしい から、大変な投資だな。これじゃ、おいそれと子沢山にはなれないね。ああ、おじいちゃん から出してもらえばいいのか。年寄りはたんまり持ってるらしいから。

しゃべりたくてウズウズの風。一人で勝手に奇声を出していたな。言葉になるのはいつ ぐらいだろう? 脳コンピュータの発達には興味があるな。硬いやつよりは面白そう。

retro on Windows

間にLL祭り対応が入っちゃって中断しちゃったけど、retoroを再開。 Windows 7でもretroが動くかと思ってやってみた。一応Windowsにもmingwの環境が 入っているんで、動くかなって軽い気持ちです。

$ make
rm -f retro
rm -f retroImage16 retroImage64
rm -f retroImage16BE retroImageBE retroImage64BE
rm -f *~
gcc -Wall vm/complete/retro.c -o retro
vm/complete/retro.c:13:21: fatal error: termios.h: No such file or directory
compilation terminated.
make: *** [retro] Error 1

幾らmingwと言えど、termiosとかは用意してないのね。探せば有るかも知れないけど、 そこまでは元気ないので、蛇でやってみる。ベンチ用のイメージは、FreeBSDで使ってた fibが組み込まれたやつを、そのまま持ってきた。

$ make python
cp vm/complete/retro.py retro
chmod +x retro
$ cd benchmarks/
$ time ../retro

real    2m53.910s
user    0m0.015s
sys     0m0.061s

ベンチって事は、比較対象が必要。この際だから、goのwindows版を入れてみた。すんなりと コンパイル出来たよ。teriosで使ってる部分がgoだと内蔵してんのかな。

$ time ../main

real    0m4.237s
user    0m0.000s
sys     0m0.062s

goはWindowsに来ても、FreeBSDと同等なスピードで働いてくれるよ。なかなか良いぞ。

gforth bench

上でbenchなんてのが出てきたので、gforthでもやってみる。gforthを作る過程で実行出来る ようになってた。

[sakae@pcbsd /usr/ports/lang/gforth/work/gforth-0.7.2]$ make bench
cp -p kernl32l.fi kernl32l.fi~
cp -p kernl32l.fi- kernl32l.fi
Each benchmark takes about 30s on a 486-66 (gcc-2.6.3 -DFORCE_REG)
time ./gforth-fast --die-on-signal -p ".:/usr/local/lib/gforth/site-forth:/usr/local/share/gforth/site-forth:/usr/local/lib/gforth/0.7.2:/usr/local/share/gforth/0.7.2:." siev.fs -e "main bye"
        0.40 real         0.37 user         0.03 sys
time ./gforth-fast --die-on-signal -p ".:/usr/local/lib/gforth/site-forth:/usr/local/share/gforth/site-forth:/usr/local/lib/gforth/0.7.2:/usr/local/share/gforth/0.7.2:." bubble.fs -e "main bye"
redefined cell  redefined list          0.52 real         0.49 user         0.03 sys
time ./gforth-fast --die-on-signal -p ".:/usr/local/lib/gforth/site-forth:/usr/local/share/gforth/site-forth:/usr/local/lib/gforth/0.7.2:/usr/local/share/gforth/0.7.2:." matrix.fs -e "main bye"
        0.25 real         0.19 user         0.06 sys
time ./gforth-fast --die-on-signal -p ".:/usr/local/lib/gforth/site-forth:/usr/local/share/gforth/site-forth:/usr/local/lib/gforth/0.7.2:/usr/local/share/gforth/0.7.2:." fib.fs -e "main bye"
        0.48 real         0.47 user         0.01 sys

また、onebench.fsってのも用意されてて、そこからも実行出来る。

s" /usr/ports/lang/gforth/work/gforth-0.7.2/onebench.fs" included
 sieve bubble matrix  fib
 0.304 0.411  0.233 0.419

Process forth finished

これを実行するコードがどうなっているか、ちょっと眺めてみると

\ many platforms don't have GNU time, so we do it ourselves

.( sieve bubble matrix  fib) cr

warnings off

: include-main-time ( addr u -- )
    cputime d+ 2>r
    included s" main" evaluate
    cputime d+ 2r> d-
    <# # # # # # # '. hold #s #> 9 over - spaces 3 - type ;

s" siev.fs"   include-main-time
s" bubble.fs" include-main-time space
s" matrix.fs" include-main-time
s" fib.fs"    include-main-time
cr bye

これの作者さんはGNU timeが何処にも有るって訳じゃないから自前でやるよって 注釈を書いてるな。cputimeが時間を計っている事は想像出来るけど、本当はどうなの? それから、d+ とか も知らないなあ。知らないものは調べてみるに限る。

調べたい単語にカーソルを合わせてC-c C-i すれば良い。

`cputime'       - duser dsystem        gforth       "cputime"
   duser and dsystem are the respective user- and system-level CPU
times used since the start of the Forth system (excluding child
processes), in microseconds (the granularity may be much larger,
however).  On platforms without the getrusage call, it reports elapsed
time (since some epoch) for duser and 0 for dsystem.
`d+'       d1 d2 - d        double       "d-plus"

ふーん、マイクロ秒単位で、消費時間が得られるんだ。ユーザーとシステムの合計(の差)が 実行時間って訳か。onebench.fsの最後のbyeを削除した後、何度か実行し、cputimeしてみた。

.s
.s <0>  ok
cputime
cputime  ok
.s
.s <4> 4211850 0 165754 0  ok

なる程、時間が積算されてくんだ。

httpd on gforth

前回のLLで何種かhttpdを取り上げた。forthにもその手のものが有るに違いない。今時webserverも 書けないような言語は嫌われるからね。PHPはあれからどうなったんだろう?

 PHP 5.4.0 から、CLI SAPI にはウェブサーバーの機能が組み込まれるようになりました。
このウェブサーバーは開発用としてのみ設計されたものであり、 実運用に使ってはいけません。 
以下にあげる拡張子のファイルについては、標準の MIME タイプを返します。 
.css, .gif, .htm, .html, .jpe, .jpeg, .jpg, .js, .png, .svg, そして .txt。
 このうち .htm と .svg については、PHP 5.4.4 以降で対応するようになりました。 

$ cd ~/public_html
$ php -S localhost:8000

これで、パワハラも跳ね返せるぞ。良かったね > PHP

嗚呼、話が逸れた。retroは多プラットフォームの方に舵を切ったようだし、httpdを サポートしようとすると土台のVMから拡張していかないとだめだろう。PHPみたいに ユーザー数も多くなく、そんなの望み薄。その点、GNUの旗の下のgforthなら、gforth.fs ってのが、しっかりと同梱されてますよ。

ファイルを開いてみると、冒頭が Shebang で始まっていて、直ぐにでも動かせそう。 とは言え、ドキュメントルートをどうするとかがどうなっているか調べtおかないといけない。 それと起動方法もね。両方共、ファイルに書いてあった。

まずは、ドキュメントルート。ハードコーディングされてたので、変更。

Variable DocumentRoot  s" /usr/local/www/htdocs/" DocumentRoot $!
\ Variable DocumentRoot  s" /srv/www/htdocs/" DocumentRoot $!
Variable UserDir       s" public_html/"     UserDir      $!

PCBSDには、/usr/local/wwwが既に用意されてたので、そこにbinとhtdocsを設置する事に したよ。いわゆるapacheの標準方式ね。あれ? logが無いのはどうして?って疑問は あえて無視。

で、起動方法は? inetdかxinetdを使ってくれーって言うレトロな方式ですよ。PCBSDも 既にinetdは封印されてた。/etc/rc.confに起動変数をセットして、昔に戻ってみる。

http stream tcp nowait/2/10   root   /usr/local/www/bin/httpd.fs

上記は、コメントに書いてあったのをFreeBSD用に移植したものだ。httpってのは、/etc/sevices ファイルを引くと80番さんとinetdは認識。inetdはアプリの起動係なんだな。

起動に制限を設ける事にした。同時接続数は2、同一IPアドレスからの接続は、1分間に10回 までって制限を付けた。

httpd.fsはいろいろなファイルをincludeしてるんで、/usr/local/www/bin内に陳列して おいたよ。

[sakae@pcbsd ~]$ ls /usr/local/www/bin/
httpd.fs        proxy.fs        socket.fs       string.fs

本当は、socket.fsって、unixっていうsub-directoryの下に置かないといけないんだ けどね。これでも動いている。って、事は、他の所にあるのを参照してんのかな? ちょっと 強引に調べてみる。

[sakae@pcbsd ~]$ strings /usr/local/bin/gforth | grep /usr/local
.:/usr/local/lib/gforth/site-forth:/usr/local/share/gforth/site-forth:/usr/local/lib/gforth/0.7.2:/usr/local/share/gforth/0.7.2

早速、アクセスしてみる。

[sakae@pcbsd ~]$ telnet localhost 80
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
get /test.html http 1.1

HTTP/1.1 200 OK
Server: Gforth httpd/1.0 (unix)
Accept-Ranges: bytes
Content-Length: 449
Connection: close
Content-Type: text/html

<html lang="en">
   :
</html>


Connection closed by foreign host.

今度はinetdを使わないで、stdinから直接httpd.fsに接続してみる。

[sakae@pcbsd ~]$ cat -- | /usr/local/www/bin/httpd.fs
get /test.html http 1.0

HTTP/1.1 200 OK
Server: Gforth httpd/1.0 (unix)
Accept-Ranges: bytes
Content-Length: 449
Connection: close
Content-Type: text/html

<html lang="en">
   :

80番ポートを使わなかったけど、データは取れるんですねぇ。まるでCGIみたいな仕組み (やり取りがパイプ)だな。

fedoraではどうかと思ってやってみると

[sakae@fedora gforth-0.7.2]$ cat -- | ./httpd.fs
sh: --silent: command not found

in file included from *OS command line*:-1
in file included from httpd.fs:273
in file included from proxy.fs:20
unix/socket.fs:48: libtool compile failed
>>>end-c-library<<<
Backtrace:
$B73BBB0C throw
$B73DD4B4 c(abort")
$B73DDB50 compile-wrapper-function1

調べてみると、debian等でも失敗して 同じエラーを出している。FreeBSDでは

[sakae@pcbsd ~]$ ls /usr/local/lib/gforth/0.7.2/libcc-named/
cstr.a          fflib.a         libffi.a        socket.a
cstr.la         fflib.la        libffi.la       socket.la
cstr.so         fflib.so        libffi.so       socket.so
cstr.so.0       fflib.so.0      libffi.so.0     socket.so.0

ちゃんと出来ているんだけどね。Linuxで誰もメンテナンスしてないって事は、見捨てられたんかな。 こういう時、土台が違うOSを動かしていると便利だな。

真面目にconfigureのlogを見ると警告が

configure: WARNING: No GNU_LIBTOOL found, skip pre-building libcc-based libraries
configure: WARNING: No GNU_LIBTOOL found, using "libtool" as name.
configure: WARNING: libcc.fs won't work until you have installed (GNU) libtool.

libtoolが入っていなかったので、入れた。そしてコンパイルしてみると

for i in libffi.fs cstr.fs unix/socket.fs; do ./gforth -e "s\" `pwd`/lib/gforth/0.7.2/libcc-named/\" libcc-named-dir-v 2! libcc-path clear-path libcc-named-dir libcc-path also-path :noname 2drop s\" /usr/local/lib/gforth/0.7.2/libcc-named/\" ; is replace-rpath" ./$i -e bye; done

libltdl is not configured
in file included from *OS command line*:-1
libffi.fs:159: open-lib failed
>>>end-c-library<<<
Backtrace:
$B736FB0C throw
$B739169C c(abort")
$B7391B60 compile-wrapper-function1

libltdlがconfig出来なかったって事は、ヘッダーファイルが無かったんだな。と言う事は ヘッダーファイルを入れろって事か。 libtool-ltdl-devel.i686 を入れたよ。今の時代、HDDが大容量になってるんで、 ヘッダーファイルぐらいは、libに同期して入れておけよ。時代錯誤なLinux流だ事。

信用出来ると思っていたdebianもfedoraもデフォで提供されてるgforthは、httpd.fsが 動かない状態で提供されてます。それが上記のケチ臭いLinux流の犠牲者だとすれば、 全く困ったものです。

まあ、httpd.fsが動くようになっても今のままのhttpd.fsでは、inetdからしか起動しないんで、 困ったものです。これもそれも車輪の再発明である systemdなんてのが悪いんだ。 おっと、inetdも昔のリソースが無い状態で動かす苦肉の策だったから、今はのびのびと って言う流儀には合わないんですがね。

fedoraでの実行例

[sakae@fedora ~]$ cat -- | src/gforth-0.7.2/httpd.fs
get /~sakae/D3/test.html http 1.0

HTTP/1.1 200 OK
Server: Gforth httpd/1.0 (unix)
Accept-Ranges: bytes
Content-Length: 568
Connection: close
Content-Type: text/html


<!DOCTYPE html>
    :

httpd on factor

factorでもWeb Serverに成れるかと思ったら、そんなの基本でっせって事で、basic/http ってのが用意されてて、サーバーにもクライアントにも変化するようになってた。 但し、部品が用意されるだけなんで、コンテンツを用意して、どこかに放り込んで おいて、サーバーを起動すれば即使えるって感じではない。

基本は部品を組み合わせていく。

USING: kernel http.server http.server.responses namespaces 
       http prettyprint ;

SINGLETON: helloworld

M: helloworld call-responder*
    2drop "hello world" "text/html" <content> ;

helloworld main-responder set 8080 httpd 

こうする事で、やっと http://localhost:8080/ して、こんにちわ世界が拝めることになる。 それにしても、部品の取り込みに長大な時間がかかるので、覚悟の事。

web app こちらを見ると、部品を組み合わせて、WebAppを作るためのように設計されてるようだ。 余り深入りしても、得る所が無いと思うので、これぐらいにしておきます。気が向いたら、 /extra/webappの下の各アプリを見ればいいんだ。

最後に、web見の方法

USE: http.client "http://www.yahoo.co.jp" http-get write