google-code-prettify

2011-07-14

AndroidのSSLSocketはマルチスレッドに対応しているのか

OpenSSLを知っている人には有名な話だと思うが、OpenSSLではひとつのソケット(SSL型)に対してSSL_read()とSSL_write()を同時に呼ぶことはできない。(実際には多くの場合は動作するが、re-negotiationが動作しない)

OpenSSLのFAQ

この仕様は、blocking IOの時に問題となる。SSL_read()でブロックしている最中に別スレッドからSSL_write()することができないのだ。

SSL上の通信が、Read,Writeがシーケンシャルに行われるような通信の場合には問題とならないが、ReadとWriteが独立して行われる通信の場合、blocking IOのSSLは使えないことになる。

AndroidのSSL部はOpenSSLを使っているが、この辺りがどうなっているのか(制限がそのままあるのか、回避されているのか)を調べてみた。

結論としては、AndroidのSSLはマルチスレッド対応している。以下、その説明。




SSLSocketの実装は、OpenSSLSocketImpl.javaにある。
SSLSocketからは、NativeCrypto.cppの関数が呼ばれている。

NativeCrypto.cppのNativeCrypto_SSL_do_handshake()で、ソケットをnon-blockingにしている。

/*
* Make socket non-blocking, so SSL_connect SSL_read() and SSL_write() don't hang
* forever and we can use select() to find out if the socket is ready.
*/
if (!setBlocking(fd.get(), false)) {
throwSSLExceptionStr(env, "Unable to make socket non blocking");
SSL_clear(ssl);
JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake => 0", ssl);
return 0;
}

NativeCrypto.cppのsslRead()とsslWrite()には、以下のコメントがある。

/*
* Helper function which does the actual writing. The Java layer guarantees that
* at most one thread will enter this function at any given time.

関数の中身を見ると、

1. non-blockingでSSL_read()/SSL_write()を呼び出す。
2. 失敗した場合は、sslSelect()を呼び、ブロックする。

としている。

結局、
・AndroidのSSLは、non-blocking IOを使っているが、上位にはblockingのAPIを提供している。
・OpenSSLのblocking IOにあるような、マルチスレッドの呼び出し制限は無い。
ということで、ユーザーにとって使いやすいAPIとなっている。

0 件のコメント: