2010-10-17 189 views
25

OpenSSL庫允許使用SSL_read從底層套接字讀取數據,並使用SSL_write寫入。這些函數可能會返回SSL_ERROR_WANT_READ或SSL_ERROR_WANT_WRITE,具體取決於它們的ssl協議需求(例如重新協商連接時)。如何在非阻塞套接字上處理OpenSSL SSL_ERROR_WANT_READ/WANT_WRITE

我真的不明白API要我怎樣處理這些結果。

將接受客戶端連接的服務器應用程序映像建立一個新的ssl會話,使底層套接字非阻塞,然後將filedescriptor添加到select/poll/epoll循環中。

如果客戶端發送數據,主循環會將其發送到ssl_read。如果返回SSL_ERROR_WANT_READ或SSL_ERROR_WANT_WRITE,那麼在這裏需要做些什麼? WANT_READ可能很容易,因爲下一個主循環迭代可能會導致另一個ssl_read。但是,如果ssl_read返回WANT_WRITE,應該調用哪些參數?爲什麼圖書館不會自己發出呼叫?

如果服務器想要向客戶端發送一些數據,它將使用ssl_write。同樣,如果返回WANT_READ或WANT_WRITE,該怎麼辦? WANT_WRITE可以通過重複剛被調用的同一個調用來回答嗎?如果返回WANT_READ,是否應該返回到主循環並讓select/poll/epoll處理這個問題?但是,首先應該寫的信息呢?

或者應該在寫入失敗後立即進行讀取?那麼,什麼防止從應用程序協議中讀取字節,然後在真正的解析器位於主循環中時不得不在應用程序的郊區某處處理呢?

回答

38

對於非阻塞套接字,SSL_WANT_READ表示「等待套接字可讀,然後再次調用此函數。」;相反,SSL_WANT_WRITE意味着「等待套接字可寫入,然後再次調用此函數。」。您可以從SSL_read()SSL_write()呼叫中獲得SSL_WANT_WRITESSL_WANT_READ

+3

清晰簡潔的解釋+1 – 2012-04-11 15:34:43

+0

這裏最好的解釋 – 2014-06-03 05:14:46

5

SSL_WANT_READ意味着SSL引擎當前無法爲您加密,因爲它正在等待更多輸入數據(作爲初始握手的一部分或作爲重新協商的一部分),因此,一旦您的下一次讀取完成並且您已經推送了通過SSL引擎到達的數據,您可以重試您的寫入操作。

同樣,SSL_WANT_WRITE意味着SSL引擎正在等待您從中提取一些數據並將其發送給對等方。

我在2002年爲Windows開發者期刊(轉載here)寫了關於使用OpenSSL的非阻塞和異步套接字,雖然本文表面上針對Windows代碼,但其他平臺的主體是相同的。本文附帶一些代碼,它將Windows上的OpenSSL與異步套接字集成,並處理整個SSL_WANT_READ/SSL_WANT_WRITE問題。

本質上,當您獲得SSL_WANT_READ時,您需要排隊出站數據,直到您完成讀取操作並將新的入站數據傳遞到SSL引擎,一旦發生這種情況,您可以重試發送出站數據。

+1

好的,從SSL_write()返回的SSL_WANT_READ可以理解,我只是在應用程序的某個地方將所有外發消息排隊,直到SSL_read()成功,然後再試一次。因此,如果緩衝時內存不足,我必須刪除應用程序消息或刪除該連接。 現在,如果SSL_read()返回SSL_WANT_WRITE並且我沒有任何數據,這意味着我必須做一個零長度的SSL_write()來滿足該請求,然後再次成功讀取? – dantje 2010-10-19 09:27:26

+1

使用SSL_WANT_WRITE,您可能會發現需要從BIO中提取併發送到另一端的數據。據我所知,您不應該通過BIO推零字節寫入。 – 2010-10-19 12:39:56

11

您是否閱讀過關於ssl_readssl_get_error的OpenSSL文檔呢?

ssl_read:

If the underlying BIO is blocking, SSL_read() will only return, once the read operation has been finished or an error occurred, except when a renegotiation take place, in which case a SSL_ERROR_WANT_READ may occur. This behaviour can be controlled with the SSL_MODE_AUTO_RETRY flag of the SSL_CTX_set_mode(3) call.

If the underlying BIO is non-blocking, SSL_read() will also return when the underlying BIO could not satisfy the needs of SSL_read() to continue the operation. In this case a call to SSL_get_error(3) with the return value of SSL_read() will yield SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE. As at any time a re-negotiation is possible, a call to SSL_read() can also cause write operations! The calling process then must repeat the call after taking appropriate action to satisfy the needs of SSL_read(). The action depends on the underlying BIO. When using a non-blocking socket, nothing is to be done, but select() can be used to check for the required condition.

ssl_get_error:

SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE

The operation did not complete; the same TLS/SSL I/O function should be called again later. If, by then, the underlying BIO has data available for reading (if the result code is SSL_ERROR_WANT_READ) or allows writing data (SSL_ERROR_WANT_WRITE), then some TLS/SSL protocol progress will take place, i.e. at least part of an TLS/SSL record will be read or written. Note that the retry may again lead to a SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE condition. There is no fixed upper limit for the number of iterations that may be necessary until progress becomes visible at application protocol level.

For socket BIOs (e.g. when SSL_set_fd() was used), select() or poll() on the underlying socket can be used to find out when the TLS/SSL I/O function should be retried.

Caveat: Any TLS/SSL I/O function can lead to either of SSL_ERROR_WANT_READ and SSL_ERROR_WANT_WRITE. In particular, SSL_read() or SSL_peek() may want to write data and SSL_write() may want to read data. This is mainly because TLS/SSL handshakes may occur at any time during the protocol (initiated by either the client or the server); SSL_read(), SSL_peek(), and SSL_write() will handle any pending handshakes.

OpenSSL是作爲一個狀態機實施。 SSL_ERROR_WANT_READ意味着更多的入站數據,而SSL_ERROR_WANT_WRITE意味着需要更多的出站數據才能在連接上取得進展。如果在ssl_read()操作中獲得SSL_ERROR_WANT_WRITE,則需要發送出站數據,或者至少等待套接字變爲可寫。如果在ssl_write()操作中獲得SSL_ERROR_WANT_READ,則需要讀取入站數據。您可以訂閱OpenSSL mailing lists。這個問題被問到很多。

+17

是的,我看了文檔。這就是我在這裏所得到的:-)現在我開始明白,SSL_WANT_READ不*要求我發出SSL_read(),SSL_WANT_WRITE也不要求我調用SSL_write(),而只是表示我應該重試當下面的套接字變得可讀或可寫時,調用剛剛返回。所以,應該將它們解釋爲SSL_WANTS_A_READABLE_SOCKET和SSL_WANTS_A_WRITEABLE_SOCKET。 – dantje 2010-10-19 09:47:12