読者です 読者をやめる 読者になる 読者になる

SnowLeopardではRubyもRailsもまともに動かない時がある

Ruby Rails Mac

昨日、会社でLeopardからSnowLeopardにアップグレードしたPCで
Railsアプリの開発をしようと思ったら、webrickが立ち上がらない。

とりあえず簡単にチェックするには

OKな場合。

ruby -rsocket -e 'p TCPServer.new("localhost","0")'
#<TCPServer:0x100154dd8>

NGな場合。

ruby -rsocket -e 'p TCPServer.new("localhost",0)'
-e:1:in `initialize': getaddrinfo: nodename nor servname provided, or not known (SocketError)
	from -e:1:in `new'
	from -e:1

さて、私のwebrickが立ち上がらない。

% ./script/server
=> Booting Mongrel (use 'script/server webrick' to force WEBrick)
=> Rails 2.1.0 application starting on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
** Starting Mongrel listening at 0.0.0.0:3000
** Starting Rails with development environment...
Exiting
/usr/local/lib/ruby/gems/1.8/gems/mongrel-1.1.5/lib/mongrel/tcphack.rb:12:in `initialize_without_backlog': getaddrinfo: nodename nor servname provided, or not known (SocketError)
	from /usr/local/lib/ruby/gems/1.8/gems/mongrel-1.1.5/lib/mongrel/tcphack.rb:12:in `initialize'
	from /usr/local/lib/ruby/1.8/drb/drb.rb:865:in `open'
	from /usr/local/lib/ruby/1.8/drb/drb.rb:865:in `open_server'
	from /usr/local/lib/ruby/1.8/drb/drb.rb:759:in `open_server'
	from /usr/local/lib/ruby/1.8/drb/drb.rb:757:in `each'
	from /usr/local/lib/ruby/1.8/drb/drb.rb:757:in `open_server'
	from /usr/local/lib/ruby/1.8/drb/drb.rb:1340:in `initialize'
	from /usr/local/lib/ruby/1.8/drb/drb.rb:1628:in `new'
	 ... 46 levels...
	from /usr/local/lib/ruby/gems/1.8/gems/rails-2.1.0/lib/commands/server.rb:39
	from /usr/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require'
	from /usr/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require'
	from ./script/server:3

DRBがエラーを出していて、mongrelでもダメでした。
これでは仕事にならないので、原因を追求しました。
このMacbookを自宅に持っていくと問題が出ないので苦労しました。
それで再現性がようやくわかりました。
おそらくSnow Leopardのgetaddrinfoのバグです。
特定の条件の時におかしな値を返すようです。
条件というのが、

host localhostを実行し、
localhost has address 127.0.0.1
localhost has IPv6 address ::1
とIPv6が出てくる場合に、
検索ドメインにドメイン名が入っているときに
getaddrinfo("localhost","0")が動かないということです。

実験してみます。

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>

main()
{
  int result;
  struct addrinfo hints, *res = NULL;
  memset(&hints, 0, sizeof(hints));
  hints.ai_socktype = SOCK_STREAM;
  //hints.ai_flags = AI_PASSIVE;
  //hints.ai_family = AF_INET;
  hints.ai_family = AF_UNSPEC;
  result=getaddrinfo("localhost", "0", &hints, &res);
  if(result==0){
    printf("OK(%d)\n",result);
  }else{
    printf("NG(%d)\n",result);
  }
}

をjikken.cという名前で保存し、

gcc jikken.c -o jikken
./jikken

コンパイルし、実行します。

のようにDHCPサーバから検索ドメイン名を引っ張ってくると

% ./jikken
NG(8)

と出ます。

のように固定IPにしてドメイン名を空にすると、

% ./jikken
OK(0)

となります。Railswebrickも立ち上げてみると、

% ./script/server
=> Booting Mongrel (use 'script/server webrick' to force WEBrick)
=> Rails 2.1.0 application starting on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
** Starting Mongrel listening at 0.0.0.0:3000
** Starting Rails with development environment...
** Erubis 2.6.2
** Rails loaded.
** Loading any Rails specific GemPlugins
** Signals ready.  TERM => stop.  USR2 => restart.  INT => stop (no restart).
** Rails signals registered.  HUP => reload (without restart).  It might not work well.
** Mongrel 1.1.5 available at 0.0.0.0:3000
** Use CTRL-C to stop.
  SQL (0.000108)   SET client_min_messages TO 'panic'
  SQL (0.000078)   SET client_min_messages TO 'notice'
  SQL (0.001031)   SELECT version FROM schema_migrations

というように、webrickも問題ありません。

のように固定IPでも検索ドメインを入れると、

% ./jikken
NG(8)

となります。当然webrickも立ち上がりません。
というわけで、とりあえずの解決方法は検索ドメインを空白にする。
ということです。今後の対応はこれから考えます。