はじめに
本ドキュメントの目的
このドキュメントは、OpenSSLのSSL_get_error関数について分かりやすく解説します。関数の役割や動作の意図、戻り値が示す意味を整理し、実装で注意すべき点を具体例を交えて説明します。
なぜ重要か
SSL_get_errorは、通信処理で発生した状態を判定するための“道しるべ”です。たとえば、電話で相手の応答がないときに原因を探すように、接続の一時的な中断や致命的なエラーを区別できます。適切に扱うと堅牢なエラーハンドリングが可能になります。
対象読者
- OpenSSLでネットワーク処理を実装する開発者
- SSL/TLSの基本を学び始めた方
- エラー原因を正確に診断したい運用担当者
前提知識
基本的なC言語の入出力やソケット処理、SSL/TLSの概念があると読みやすいです。専門用語は最小限にし、例を使って補足します。
本書の構成
第2章で関数の詳細を掘り下げ、第3章で戻り値ごとの意味を整理します。第4章では実装上の注意点を示し、第5章で全体のまとめとエラーハンドリングの重要性を述べます。
SSL_get_error関数の詳細解説
概要
SSL_get_errorは、SSL/TLSの入出力関数(例: SSL_connect, SSL_read, SSL_write)を呼んだ直後に使い、失敗理由を判定します。直前のI/O関数の戻り値とSSLオブジェクトを渡します。
引数と使い方の注意点
- 第1引数: SSLオブジェクト
- 第2引数: 直前のI/O関数の戻り値(int)
呼び出しは同じスレッド内で行い、呼び出しの間に他のOpenSSL関数を呼んではいけません。したがって、エラー判定は速やかに行ってください。
呼び出し順の例(簡単な流れ)
- rv = SSL_read(ssl, buf, len)
- if (rv <= 0) err = SSL_get_error(ssl, rv)
- errの値に応じて再試行や接続終了を判断
よくある戻り値の扱い(例)
- SSL_ERROR_NONE: 成功(rv > 0)
- SSL_ERROR_ZERO_RETURN: 正常にシャットダウンされた
- SSL_ERROR_WANT_READ / WANT_WRITE: ノンブロッキングで再試行が必要
- SSL_ERROR_SYSCALL: システムコールでのエラー。errnoを確認
- SSL_ERROR_SSL: ライブラリ内部のエラー。詳細はERR_get_errorで取得
実務上のポイント
ノンブロッキングIOではWANT_*を受け取りイベントループで読み書き可能になるまで待ちます。SYSCALLやSSLの内部エラーではログを残し、必要に応じて接続を切る判断をします。具体例を交え、明確に分岐処理を書くとトラブルを防げます。
SSL_get_errorの戻り値一覧
SSL_get_errorが返す値は、SSL通信の状態を読み取る手がかりになります。ここでは代表的な戻り値を分かりやすく説明します。
- SSL_ERROR_NONE (0)
- 意味: 処理が正常に完了しました。
-
例: SSL_readがデータを返したとき。次の処理に進めます。
-
SSL_ERROR_ZERO_RETURN
- 意味: ピア(相手)が正常に接続を閉じました。
-
例: クライアントがTLSのシャットダウンを行った場合。ソケットを閉じて終了します。
-
SSL_ERROR_WANT_READ
- 意味: 読み込みが完了しておらず、もう一度読み込みを試す必要があります。
-
対処: ソケットが読み込み可能になるまで待ってから再試行します。ノンブロッキングの場合はselect/pollで監視します。
-
SSL_ERROR_WANT_WRITE
- 意味: 書き込みが完了しておらず、書き込み可能になるのを待つ必要があります。
-
対処: 書き込み可能になったら再試行します。バッファリングの有無に注意してください。
-
SSL_ERROR_WANT_CONNECT
- 意味: 非同期の接続処理が進行中で、接続完了を待つ必要があります。
-
対処: 接続完了イベントを待ってから再試行します。
-
SSL_ERROR_WANT_ACCEPT
- 意味: 非同期のaccept処理を待つ必要があります(サーバ側)。
-
対処: acceptが可能になるまで待ってから再試行します。
-
SSL_ERROR_SYSCALL
- 意味: システムコールレベルのエラーが発生しました。errnoやログを確認します。
- 対処: errnoやOpenSSLのエラースタックを確認し、再試行か終了を判断します。
それぞれの値で取るべき操作は明確です。非ブロッキングI/Oでは再試行の管理が特に重要になります。
実装上の重要なポイント
SSL_ERROR_WANT_READ/WRITEへの対処
SSL_readやSSL_writeは、ソケットがブロッキングでない場合にSSL_ERROR_WANT_READやSSL_ERROR_WANT_WRITEを返すことがあります。これは失敗ではなく「処理を続けるには読み込み/書き込み可能になるまで待ってほしい」という合図です。例えば書き込みでWANT_WRITEが返ったら、ソケットが書き込み可能になったら再度SSL_writeを呼びます。
ハンドシェイクが任意に起こる点
TLS/SSLのハンドシェイクは初回だけでなくデータ送受信の途中でも発生します。これにより、読み書き中に予期せずWANT_READ/WANT_WRITEが返ることがあります。したがって各呼び出しでSSL_get_errorを確認し、適切に再試行してください。
エラーキューの管理
OpenSSLはエラーキューを持ちます。古いエラーが残ると誤判断の原因になります。操作前にERR_clear_error()でキューをクリアし、失敗時はERR_get_errorで詳細を取得してログ化してください。ログは問題再現に役立ちます。
ノンブロッキングI/Oでの待ち方
select、poll、epollなどでソケットの読み書き可能を待ちます。例:selectで書き込み可能になったらSSL_writeを再呼び出し、読み込み可能ならSSL_readを再呼び出し。タイムアウトと再試行回数を設けてハングを防ぎます。
再試行、部分書き込み、終了処理
SSL_writeは要求したバイト数を全て書かないことがあります。返り値とSSL_get_errorを見て不足分をループで送信してください。致命的エラーやSSL_ERROR_SYSCALLなどは接続を閉じ、リソースを解放します。実装では明確な状態管理とログ出力を心がけるとトラブルが減ります。
まとめ
SSL_get_error関数はOpenSSLでの通信エラーを分類する中心的な仕組みです。戻り値ごとに対応が異なり、特にSSL_ERROR_WANT_READ/SSL_ERROR_WANT_WRITEは再試行を示します。非ブロッキングソケットでは読み書き可能になるまで待ち、再度同じSSL_read/SSL_writeを呼ぶ設計が必要です。
実装上の重要ポイント:
– WANT系は再試行ロジックを用意する(イベントループやselect/poll/epollで待機)。
– SSL_ERROR_ZERO_RETURNは接続の正常終了を示すためクリーンなシャットダウンを行う。
– SSL_ERROR_SYSCALLやSSL_ERROR_SSLは細かくログを残し、errnoやERR_get_errorで原因を調査する。
– リソース管理(SSL_shutdown, SSL_free, close)を忘れない。
正確なエラー処理を実装すると、堅牢で信頼性の高いTLS/SSL通信を提供できます。












