GSoap工作原理簡析
前言
因為工作原因,接觸GSoap已有大半年時間,春節閒來無事,簡單寫一下半年來對GSoap的理解。服務端
int main() { #ifdef WITH_OPENSSL //1、初始化OpenSSL(系統會自動初始化SSL,故可跳過此函式) //函式會呼叫SSL_library_init()、OpenSSL_add_all_algorithms()、SSL_load_error_strings()等,用於初始化SSL、載入加密演算法及錯誤資訊等。初始化後soap_ssl_init_done=1,表示已初始化以避免重複初始化。 soap_ssl_init(); //2、對於多執行緒應用,OpenSSL要求顯示安裝互斥鎖,由此需呼叫 CRYPTO_thread_setup()、CRYPTO_thread_cleanup()
soap_ssl_server_context:flags
巨集 值 描述 SOAP_SSL_NO_AUTHENTICATION 0x00 不啟用證書驗證,通常用於測試 SOAP_SSL_REQUIRE_SERVER_AUTHENTICATION 0x01 服務端需對客戶端進行身份驗證 SOAP_SSL_REQUIRE_CLIENT_AUTHENTICATION 0x02 客戶端需對服務端進行身份驗證 SOAP_SSL_SKIP_HOST_CHECK 0x04 不檢查證書中主機的common name SOAP_SSL_ALLOW_EXPIRED_CERTIFICATE 0x08 不檢查證書的失效日期 SOAP_SSL_NO_DEFAULT_CA_PATH 0x10 不使用 default_verify_paths SOAP_SSL_RSA 0x20 使用RSA SOAP_SSLv3 0x40 SSL v3 only SOAP_TLSv1 0x80 TLS v1 only SOAP_SSLv3_TLSv1 0x00 SSL v3 and TLS v1 support by default (no SSL v1/v2) SOAP_SSL_CLIENT 0x100 client context SOAP_SSL_DEFAULT SOAP_SSL_REQUIRE_SERVER_AUTHENTICATION“或操作符” SOAP_SSLv3_TLSv1 soap_ssl_accept()
簡介:soap_accept() 之後呼叫,用於執行 SSL/TLS 握手,建立安全的SSL通道。作用:
1)fsslauth();
// 實際呼叫的是ssl_auth_init()。2)若未初始化OpenSSL,呼叫soap_ssl_init()。
3)soap->ctx = SSL_CTX_new(SSLv23_method());
// 建立SSL所用的method、申請SSL會話的環境(建立新的 SSL_CTX物件 作為建立 TLS/SSL 的框架)4)SSL_CTX_set_mode(soap->ctx,SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_AUTO_RETRY);
// 設定握手模式,允許寫完或部分寫完時成功返回,SSL_write(…, n) to return r with 0 < r < n。只有握手並且成功完成後,read/write才會返回5)RAND_load_file(soap->randfile, -1);
// 從隨機數種子檔案中讀取資料,-1:讀取整個檔案6)SSL_CTX_load_verify_locations(soap->ctx, soap->cafile, soap->capath);
// 載入證書:SSL_CTX*,證書檔案的名稱,證書檔案的路徑7)SSL_CTX_set_client_CA_list(soap->ctx, SSL_load_client_CA_file(soap->cafile));
// SOAP_SSL_REQUIRE_CLIENT_AUTHENTICATION:需要客戶端驗證時,伺服器從CAfile載入可信任CA證書,併發往客戶端8)SSL_CTX_set_default_verify_paths(soap->ctx);
// 若!SOAP_SSL_NO_DEFAULT_CA_PATH,即使用預設驗證路徑,則從預設路徑載入CA證書9)SSL_CTX_use_certificate_chain_file(soap->ctx, soap->keyfile);
// 為SSL載入本應用證書所屬的證書鏈10)SSL_CTX_set_default_passwd_cb_userdata(soap->ctx, (void*)soap->password);
// 設定讀取私鑰的密碼11)RSA *rsa = RSA_generate_key(SOAP_SSL_RSA_BITS, RSA_F4, NULL, NULL);
SSL_CTX_set_tmp_rsa(soap->ctx, rsa);
// 若使用RSA金鑰交換演算法,生成金鑰對; 設定RSA金鑰
// 若採用非RSA金鑰交換演算法,則根據指定的演算法 生成並設定金鑰引數12)SSL_CTX_set_verify(soap->ctx, mode, soap->fsslverify);
// 指定驗證方式,mode:是否驗證客戶端或服務端等,fsslverify:驗證結果回撥函式,主要用於當驗證失敗時輸出錯誤資訊。13)SSL_CTX_set_verify_depth(soap->ctx, 9);
// 設定允許ctx可驗證的最大證書鏈深度14)struct soap *soap;
soap->ssl = SSL_new(soap->ctx);
// 申請一個SSL套接字15)BIO *bio = BIO_new_socket((int)sk, BIO_NOCLOSE);
// 根據給定的sock返回一個socket型別的BIO SOAP_SOCKET sk —>>> 輸入引數16)SSL_set_bio(soap->ssl, bio, bio);
// 將SSL與bio聯絡起來17)r = SSL_accept(soap->ssl);
// 等待一個TLS/SSL客戶端啟動TLS/SSL握手18)tcp_select();
// 採用select模型,判斷是否有新的客戶端連線或可讀資料到達19)若指定:SOAP_SSL_REQUIRE_CLIENT_AUTHENTICATION,即伺服器需對客戶端進行身份驗證,則:
SSL_get_verify_result(soap->ssl);
// 對SSL中證書進行驗證,並返回驗證結果
// 若驗證通過,則:
X509 *peer = SSL_get_peer_certificate(soap->ssl);
// 從SSL套接字中提取對方的證書資訊
X509_free(peer);
// 釋放證書20)若soap指定了recv_timeout/send_timeout,則soap被設定為阻塞模式,否則為非阻塞模式。
serve()
soap_begin_serve(struct soap*):
// 開始處理soap
具體包括:
1)soap_begin(soap);
// 初始化soap的成員變數,並釋放可能存在的記憶體佔用2)soap_begin_recv(soap);
// 準備接收資料。實際上在這裡就完成了報文的接收。
// 內部呼叫了函式:#define soap_get1(soap) (((soap)->bufidx>=(soap)->buflen && soap_recv(soap)) ? EOF : (unsigned char)(soap)->buf[(soap)->bufidx++]),該函式將報文全部存入緩衝區soap->buf,bufidx標明報文長度,buflen標明buf緩衝區長度。3)soap_envelope_begin_in(struct soap *soap);
// 從buf中找尋envelope開始標籤(begin),in代表是從buf中解析結構 out代表把結構填充到buf。4)soap_recv_header(struct soap *soap);
// 解析xml資料放置於soap->header。5)soap_body_begin_in(soap));
// 與前面的兩個函式功能類似。dispatch():
// 將soap->tag與各介面名逐一對比,匹配成功後,呼叫相應介面函式。