Ubuntu Hardy で gethostbyname() をやや追い
Ubuntu Hardy でリモート smb サーバに nautilus でつなぐと,とっても時間がかかったり timeout したり,という現象がでて困っています。で,ちょっと追ってみました。現時点までのメモです(まだ解決していない)。
see ぐあ間違えてリンクしてた - daily dayflower
といっても普通の環境の方には参考にならないでしょう。というのは私の環境では nsswitch によるホスト名解決で libnss_wins.so
を利用しているからです。それ関係あるの?という感じですが,後々関係してきます。
これまでの調査*1でわかったのは下記の事実。
- gvfsd-smb が悪いのではなく libsmbclient の部分で遅延が発生しているようである
デフォルトで smb.conf
の name resolve order
は lmhosts host wins bcast
。bcast
を頭に持ってくると libsmbclient は(やや遅いものの*2)きちんと動く。host
が怪しい。
libsmbclient のログを追っていくと libsmb/namequery.c: resolve_hosts()
から帰っていなさそうなことがわかる。ここで利用しているのは gethostbyname()
という関数。
gethostbyname()
関数(でもこれ普通に使う関数だよな)を直接触って動かすとどうなる?
/* test.c */ #include <stdio.h> #include <netdb.h> int main(int argc, char *argv[]) { struct hostent *hp; hp = gethostbyname(argv[1]); if (hp) { fprintf(stderr, "h_name: %s\n", hp->h_name); } return 0; }
ほんとに素で gethostbyname()
を呼んでいるだけ。
$ gcc -Wall -g -c -o test.o test.c $ gcc -Wall -g -o test test.o $ ./test SMB_SERVER_NAME *** glibc detected *** ./test: realloc(): invalid pointer: 0xb7f2f06c *** ======= Backtrace: ========= /lib/tls/i686/cmov/libc.so.6(realloc+0x39c)[0xb7c409ec] /lib/tls/i686/cmov/libc.so.6(realloc+0x3c)[0xb7c4068c] /lib/libnss_wins.so.2(Realloc+0x8b)[0xb78a5e9b] /lib/libnss_wins.so.2(realloc_array+0x43)[0xb78a5f83] /lib/libnss_wins.so.2(debug_add_class+0x89)[0xb788e499] /lib/libnss_wins.so.2(debug_init+0x88)[0xb788e628] /lib/libnss_wins.so.2(setup_logging+0x22)[0xb788e662] /lib/libnss_wins.so.2(_nss_wins_gethostbyname_r+0x2f2)[0xb78397f2] /lib/tls/i686/cmov/libc.so.6(gethostbyname_r+0x198)[0xb7cbf6a8] /lib/tls/i686/cmov/libc.so.6(gethostbyname+0xd8)[0xb7cbef58] ./test[0x80484e5] /lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe0)[0xb7be7450] ./test[0x8048461] ======= Memory map: ======== ...... snip snip snip ...... abort ./test SMB_SERVER_NAME
ぎゃぼーん。abort してしまった。
libc:gethostbyname()
→ libc:gethostbyname_r
→ _nss_wins_gethostbyname_r()
という流れ。ここまでは nsswitch で nss_wins を利用しているから理解可能。が,どうもその中で,デバッグログ出力モジュールの initialize 時に realloc が fail しているみたい。こんなの追いきれるのかな。
ちょっと風変わりだけど直接 _nss_wins_gethostbyname_r()
を呼んでみる。
#include <stdio.h> #include <netdb.h> #include <nss.h> typedef enum nss_status NSS_STATUS; NSS_STATUS _nss_wins_gethostbyname_r(const char *hostname, struct hostent *he, char *buffer, size_t buflen, int *h_errnop); int main(int argc, char *argv[]) { static char buffer[4096]; struct hostent he; int h_errno; _nss_wins_gethostbyname_r(argv[1], &he, buffer, sizeof(buffer), &h_errno); fprintf(stderr, "h_name: %s\n", he.h_name); return 0; }
これではどうか。
$ gcc -Wall -g -c -o test.o test.c $ gcc -Wall -g -o test test.o /lib/libnss_wins.so.2 $ ./test SMB_SERVER_NAME h_name: SMB_SERVER_NAME
きちんとうまくいく。
ちなみにコマンドラインから普通に名前解決をするだけなら問題ない。
$ ping SMB_SERVER_NAME PING SMB_SERVER_NAME (192.168.0.102) 56(84) bytes of data. 64 bytes from LOCAL_HOST (192.168.0.101): icmp_seq=1 ttl=64 time=1.20 ms 64 bytes from LOCAL_HOST (192.168.0.101): icmp_seq=1 ttl=64 time=1.76 ms ...... snip snip snip ......
このへんで手詰まりです。RH 系でどうなのか試したいけどめんどくさい。
全然違うプログラム経由だけど同じ固まり方をしている例→ Ubuntu Forums