SSL_read, SSL_write での SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE と、SSL_pending の話
TLS/SSL による通信をやりたい場合、OpenSSL を使えば簡単に実装することができる。
具体的には、recv(2), send(2) を直に発行するノリで、SSL_read(3), SSL_write(3) を使えばいい……と思っていたが、そうではないらしい。
ということで、調べたことをつらつら書いてみる。なお、以下は socket が non-blocking であることを想定して書いている。
それから、OpenSSL をそこまで読み込んだわけではないので、間違っているかもしれない。ツッコミ大歓迎!
SSL_read での SSL_ERROR_WANT_READ. SSL_write での SSL_ERROR_WANT_WRITE
データの送信を行おうとしたときに TCP/IP のバッファがいっぱいで積めない場合、send は EAGAIN でエラーする。
同様に SSL_write は SSL_ERROR_WANT_WRITE を返す。この時、socket が writable になったら、全く同じ引数で SSL_write を呼ばなければならない。
WARNING
When an SSL_write() operation has to be repeated because of
SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, it must be repeated with
the same arguments.When calling SSL_write() with num=0 bytes to be sent the behaviour is
undefined.
recv の場合は、TCP/IP のバッファが空であった場合に EAGAIN でエラーする。
同様に SSL_read は SSL_ERROR_WANT_READ でエラーする。この時 SSL_write と同じで、socket が readable になったら、全く同じ引数で SSL_read を呼ばなければならない。
ここで注意しなければならないのが、select(2) で readable だったとしても、SSL_read が SSL_ERROR_WANT_READ でエラーすることがあるという点。
TLS/SSL では、データはある程度ブロックに分けられた上で、暗号化されて送受信されているため、1ブロック分全部そろっていないとデコードできない。よって、中途半端にデータを受信した場合にも SSL_ERROR_WANT_READ が返るということになる。
SSL_read での SSL_ERROR_WANT_WRITE. SSL_write での SSL_ERROR_WANT_READ
ややこしい事に、先ほどとは逆の理由でエラーすることがある。
OpenSSL では、SSL_read, SSL_write の延長上でネゴシエーション処理が実行されることがあるために、read しようとしたのに WANT_WRITE, write しようとしたのに WANT_READ が返ってきてしまう。
よって、先程の仕様とあわせると、
しないといけない。
すなわち……
SSL_read | SSL_write | |
SSL_ERROR_WANT_READ でエラー | select(readable), SSL_read | select(readable), SSL_write |
SSL_ERROR_WANT_WRITE でエラー | select(writable), SSL_read | select(writable), SSL_write |
これはメンドクサイですね…。
SSL_pending
更に、SSL_pending という物がある。
この関数は、ssl オブジェクトのバッファから block せずに読み取り可能な byte 数を返すものである。
ここで注意しなければならないのが、socket が readable ではない場合にも ssl オブジェクトのバッファにデータが乗っていることがあるということである。*1
これを考慮すると、select で readable か判定する前に SSL_pending で SSL_read *2可能かどうかチェックする必要性が見えてくる。
ただし、次の記載が man に有って、少々気にはなる。
BUGS
(snip)Up to OpenSSL 0.9.6, SSL_pending() does not check if the record type of
pending data is application data.