很不幸,openssl的底層實作不是線程安全的,雖然我可以通過我自己實作的鎖來安全的在不同的線程中使用同一個 ssl連接配接,也就是一個ssl指針可以在多個線程中共用,但是我們能看到的最底層也就是這個SSL類型的指針了,這也是我們可以保護的最底層了,再往下的 層次中該如何實作線程互斥呢?大緻看了一下openssl的代碼,發現在底層加密的時候用到了很多的共享的資料結構或者共享變量,如此一來,雖然比較上層 的SSL指針可以很好的被保護,但是一旦兩個線程同時讀寫而同時調用加密解密函數的話會很顯然的用到那些共享變量和共享資料結構,如此一來就很容易出錯, 比如我遇到的就是本來要SSL_read出100個位元組的資料,可是可能由于SSL_write此時修改了資料結構,我的程式異常崩潰,分析dmp檔案發 現是由于s3_read_bytes中将讀取資料的長度填充成了0xedffffff,危險啊!
可是怎麼解決這個問題呢?總要有解決的辦法啊,是的,有辦法,openssl提供了幾個接口函數用于設定一些回調函數,在openssl本身它也自帶了一 個,在th-lock.c中實作。這兩個接口函數是:void CRYPTO_set_locking_callback(void (*func)(int mode,int type, const char *file,int line))設定加鎖解鎖回調函數;void CRYPTO_set_id_callback(unsigned long (*func)(void))設定得到線程id回調函數。其中我覺得第一個非常有創意,将如何加鎖和解鎖留給使用者自己去實作,這就在庫的底層将機制和使用者 的政策分離中出來,并且底層可以保持一份平台無關的加密和解密代碼,各個不同的作業系統平台可以提供自己實作的加鎖和解鎖回調函數,并且如果使用者隻是跑單 線程,那麼加鎖和解鎖會帶來很大不必要的開銷,于是對共享資料的保護就成了可選的選擇了,總之,政策不會污染機制,一切分得很清!對于上面的接口設定的回 調函數,在windows平台就是:
void win32_locking_callback(int mode, int type, char *file, int line)
{
本文轉自 dog250 51CTO部落格,原文連結:http://blog.51cto.com/dog250/1273969