SnowLeopardではRubyもRailsもまともに動かない時がある
昨日、会社で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)
% ./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も立ち上がりません。
というわけで、とりあえずの解決方法は検索ドメインを空白にする。
ということです。今後の対応はこれから考えます。