« Core Foundation Hacks / iPhoneでも同じように動くのか? | ホーム | ドコモ版iPhoneは出ない たぶん出ないと思う 出ないんじゃないかな »
2011年5月24日
Core Foundationを知る / CFHostでエラーハンドリング
さて、プログラミングは正常系ばかりではだめで、エラーもちゃんと扱えるようにしとかないといけない。とりわけネットワークプログラミングについては特にそれが言えるんじゃないでしょうか。並のPCでも最近は潤沢なメモリ事情を拝啓にすれば、malloc()がNULLを返すことはそうそう無いと看做すことはできても(でも危険だよ!)、それにくらべればネットワークは格段に不確実であり、名前が引けなかったり、TCPコネクションが確立できなかったりすることは普通にある。正常系以上にエラー系におけるAPIの挙動はぜひ把握しておきたい。
前のエントリまででCFHostを非同期による解決例を追ったので、それに続けて話を進めてみます。
○ネットワークが無効な場合
○DNSサーバが応答しない場合
上記2例については、いずれの場合もコールバック関数(CFHostClientCallBack)の呼び出しにエラー(CFStreamError)を渡される。具体的には、CFStreamErrorのdomainフィールドに12(kCFStreamErrorDomainNetDB)、errorフィールドに8(EAI_NONAME)が与えられた状態でのコールバックとなる。
domainがkCFStreamErrorDomainNetDBだった場合、errorコードは/usr/include/netdb.hに定義されている通りであるとはCFHost Referenceに書かれてある通りなのだが、当のnetdb.hを読んでみるとEAI_XXX、すなわちgetaddrinfo()のエラーコードが定義されているのみである。つまるところ、CFHostの下位レイヤーではgetaddrinfo()が使われ、そのエラーコードがCFStreamErrorに設定されてコールバックされるということなのだろう。
○存在しない名前を引いた場合
DNS的に言えばNXDOMAINだったときの話。この時も、コールバックで受け取るパラメータとしては上記2項と同じであり、domain = 12およびerror = 8が設定されたCFStreamError構造体が渡されることになる。EAI_NONAMEの意味からすればそのとおりではあるのだけれども、上記二つと区別がつかないというのは何となく納得が行かない気も、しないでもない。まあ、区別をつけたくば他の方法を使えということなのだろう。
○CFHostGetAddresses()の第二引数(Boolean *hasBeenResolved)について
上記"CFHost Reference"にあるように、CFHostGetAddresses()は名前解決の完了したCFHostオブジェクトを第一引数に持ち、名前解決を済ませたことによって得られたsockaddr構造体を生のバイト列としてCFDataオブジェクトにし、それをCFArray配列オブジェクトとして返すという仕様の関数である。
ただし、前述のようにいくつかの要因によって名前解決が出来なかった場合もあり、その際にはエラーコード指定の上でCFHostClientCallBack関数が呼び出される訳だが、そのエラー発生時のコールバック発生後にCFHostGetAddresses()関数を使うと、第二引数hasBeenResolvedは、名前解決ができたできないに関わらずTRUEが与えられるらしい点に注意せねばいけない模様。つまり、名前解決ができたかどうかはこの第二引数から得られる値で確かめることはできず、もっぱら返値が非NULL(何らかのCFArrayオブジェクト)かどうかでしか分からないらしい、ということである。
挙動から見る限りは、この第二引数は単にコールバック関数が呼ばれたかどうか、すなわち「名前解決の処理がおわったかどうか」だけを見ることができる、と看做したほうが自然なようである。
トラックバック(0)
トラックバックURL: http://foursics.jp/cgi-bin/mt/mt-tb.cgi/342
コメントする