• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-162  評(píng)論-223  文章-30  trackbacks-0
               Web服務(wù)器為了支持https訪問(wèn),通常會(huì)使用第三方庫(kù)openssl實(shí)現(xiàn),而且為了高性能采用異步事件驅(qū)動(dòng)模型,因此連接套接字被設(shè)為非阻塞類型,本文在nginx ssl模塊的基礎(chǔ)上,簡(jiǎn)化提取它的核心框架,使用面向?qū)ο蟮姆绞矫枋觯瑥奈帐帧⒆x寫和關(guān)閉3個(gè)方面進(jìn)行了分析,由于這3個(gè)操作都是異步的,因此操作失敗后要調(diào)用SSL_get_error來(lái)獲取錯(cuò)誤碼,有如下4種情況。
               ● SSL_ERROR_WANT_READ:操作沒完成,需要在下一次讀事件中繼續(xù)
               ● SSL_ERROR_WANT_WRITE:操作沒完成,需要在下一次寫事件中繼續(xù)
               ● SSL_ERROR_ZERO_RETURN:連接正常關(guān)閉
               ● 其它:連接出錯(cuò)
              
               下面的示例代碼使用了libevent實(shí)現(xiàn)IO事件驅(qū)動(dòng),connection表示普通連接類,假設(shè)已經(jīng)處理好了http數(shù)據(jù)的邏輯,實(shí)現(xiàn)在成員函數(shù)handle_read和handle_write內(nèi),虛函數(shù)recv、send和close分別調(diào)用系統(tǒng)的API recv、send和close;ssl_conn_t表示安全連接類,由于只是IO處理不同:收到數(shù)據(jù)后解密,發(fā)送數(shù)據(jù)前加密。解密后的操作和connection是一樣的,因此ssl_conn_t繼承connection,重寫了recv、send和close,其中close調(diào)用了shutdown。

            異步握手
               當(dāng)在SSL端口接受到連接時(shí),首先要進(jìn)行握手,握手成功后才能收發(fā)數(shù)據(jù),如果握手失敗而且返回前2種錯(cuò)誤碼,那么要在下一次操作中繼續(xù)握手。
             1void ssl_conn_t::empty_handler(short ev)
             2{
             3}

             4
             5void ssl_conn_t::handshake_handler(short ev)
             6{
             7    handshake();
             8}

             9
            10void ssl_conn_t::handshake()
            11{
            12    int ret = do_handshake();    
            13
            14    switch(ret){
            15        case OP_OK: 
            16            read_handler_ = &connection::handle_read;
            17            write_handler_ = &connection::handle_write;
            18            handle_read(EV_READ);
            19            break;
            20                 
            21    }

            22}

            23
            24int ssl_conn_t::do_handshake()
            25{
            26    ssl_clear_error();
            27
            28    int ret = SSL_do_handshake(ssl_);
            29    if(1==ret){
            30        
            31        return OP_OK;
            32    }

            33    
            34    int sslerr = SSL_get_error(ssl_,ret), err;
            35    switch(sslerr){
            36        case SSL_ERROR_WANT_READ:
            37            read_handler_ = (io_handler)&ssl_conn_t::handshake_handler;
            38            write_handler_ = (io_handler)&ssl_conn_t::empty_handler;    
            39            return OP_AGAIN;
            40
            41        case SSL_ERROR_WANT_WRITE:
            42            read_handler_ = (io_handler)&ssl_conn_t::empty_handler;
            43            write_handler_ = (io_handler)&ssl_conn_t::handshake_handler;    
            44            return OP_AGAIN;
            45         
            46    }
                                
            47}
                以上do_handshake是核心函數(shù),調(diào)用了SSL_do_handshake來(lái)實(shí)現(xiàn)握手,當(dāng)SSL_do_handshake失敗時(shí),如果返回SSL_ERROR_WANT_READ,就改變讀函數(shù)指針為handshake_handler,寫函數(shù)指針為empty_handler;如果返回SSL_ERROR_WANT_WRITE,就改變讀函數(shù)指針為empty_handler,寫函數(shù)指針為handshake_handler。handshake_handler實(shí)現(xiàn)在讀寫事件中繼續(xù)處理握手,而empty_handler是個(gè)空函數(shù),什么也不做。
               
            異步讀寫
               對(duì)于讀操作失敗,如果返回SSL_ERROR_WANT_WRITE,那么說(shuō)明要在下一次寫事件中繼續(xù)讀數(shù)據(jù),因此要改變寫函數(shù)指針,使其讀數(shù)據(jù),當(dāng)讀成功后,要還原寫函數(shù)針,并激發(fā)一次寫事件;對(duì)于寫操作失敗,如果返回SSL_ERROR_WANT_READ,那么說(shuō)明要在下一次讀事件中繼續(xù)寫數(shù)據(jù),因此要改變讀函數(shù)指針,使其寫數(shù)據(jù),當(dāng)寫成功后,要還原讀函數(shù)指針,并激發(fā)一次讀事件。如果不還原讀或?qū)懞瘮?shù)指針,那么會(huì)發(fā)生寫或讀混亂;還原后,要激發(fā)一次讀或?qū)懯录@是為了延續(xù)IO事件的進(jìn)行,防止讀寫?zhàn)I死。
             1ssize_t ssl_conn_t::recv(void *buf,size_t len)
             2{
             3    ssl_clear_error();
             4
             5    int ret = SSL_read(ssl_,buf,len);
             6    if(ret>0){
             7        if(old_write_handler_){
             8            write_handler_ = old_write_handler_;
             9            old_write_handler_ = NULL;
            10            active_event(false);
            11        }

            12        return ret;
            13    }

            14
            15    int sslerr = SSL_get_error(ssl_,ret), err;
            16    switch(sslerr){
            17        case SSL_ERROR_WANT_READ:
            18            return OP_AGAIN;
            19
            20        case SSL_ERROR_WANT_WRITE:
            21            if(NULL==old_write_handler_){
            22                old_write_handler_ = write_handler_;
            23                write_handler_ = (io_handler)&ssl_conn_t::write_handler;
            24            }

            25            return OP_AGAIN;
            26           
            27    }

            28}

            29
            30void ssl_conn_t::write_handler(short ev)
            31{
            32    (this->*read_handler_)(EV_WRITE);
            33}

            34
            35ssize_t ssl_conn_t::send(const void *buf,size_t len)
            36{
            37    ssl_clear_error();
            38
            39    int ret = SSL_write(ssl_,buf,len);
            40    if(ret>0){
            41        if(old_read_handler_){
            42            read_handler_ = old_read_handler_;
            43            old_read_handler_ = NULL;
            44            active_event(true);
            45        }

            46        return ret;
            47    }

            48
            49    int sslerr = SSL_get_error(ssl_,ret), err;
            50    switch(sslerr){
            51        case SSL_ERROR_WANT_WRITE:
            52            return OP_AGAIN;
            53
            54        case SSL_ERROR_WANT_READ:
            55            if(NULL==old_read_handler_){
            56                old_read_handler_ = read_handler_;
            57                read_handler_ = (io_handler)&ssl_conn_t::read_handler;
            58            }

            59            return OP_AGAIN;
            60        
            61    }

            62}

            63
            64void ssl_conn_t::read_handler(short ev)
            65{
            66    (this->*write_handler_)(EV_READ);
            67}
                以上recv調(diào)用SSL_read,如果失敗并且返回SSL_ERROR_WANT_WRITE,就保存老的寫函數(shù)指針,改變寫函數(shù)指針為write_handler,write_handler實(shí)現(xiàn)在寫事件中繼續(xù)讀數(shù)據(jù);send調(diào)用SSL_write,如果失敗并且返回SSL_ERROR_WANT_READ,就保存老的讀函數(shù)指針,改變讀函數(shù)指針為read_handler,read_handler實(shí)現(xiàn)在讀事件中繼續(xù)寫數(shù)據(jù)。

            異步關(guān)閉
               當(dāng)握手或讀寫因連接關(guān)閉或出錯(cuò)而失敗時(shí),就要關(guān)閉連接了,如果失敗并且返回SSL_ERROR_WANT_READ或SSL_ERROR_WANT_WRITE,那么要在下一次讀或?qū)懯录欣^續(xù)關(guān)閉。在這里,為了收到對(duì)方發(fā)送的協(xié)議退出包而完全退出,等待30秒再關(guān)閉,如果超時(shí)就直接關(guān)閉。
             1void ssl_conn_t::shutdown(bool is_timeout/*=false*/)
             2{
             3    if (do_shutdown(is_timeout) != OP_AGAIN)
             4        delete this;
             5}

             6
             7int ssl_conn_t::do_shutdown(bool is_timeout)
             8{
             9    int  ret,mode;
            10
            11    if(is_timeout){
            12        mode = SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN;
            13        SSL_set_quiet_shutdown(ssl_,1);
            14    }
            else{
            15        
            16    }

            17    SSL_set_shutdown(ssl_,mode);
            18
            19    ssl_clear_error();
            20
            21    ret = SSL_shutdown(ssl_);
            22    if(1==ret)
            23        return OP_OK;
            24
            25    int sslerr = SSL_get_error(ssl_,ret), err;
            26    switch(sslerr){
            27        
            28        case SSL_ERROR_WANT_READ:
            29        case SSL_ERROR_WANT_WRITE:
            30            read_handler_ = (io_handler)&ssl_conn_t::shutdown_handler;
            31            write_handler_ = (io_handler)&ssl_conn_t::shutdown_handler;
            32
            33            if(SSL_ERROR_WANT_READ==sslerr){
            34                struct timeval tv;
            35                tv.tv_sec = 30,tv.tv_usec = 0;
            36                add_event(true,tv);
            37            }

            38            return OP_AGAIN;
            39        
            40    }

            41}

            42
            43void ssl_conn_t::shutdown_handler(short ev)
            44{
            45    shutdown(ev&EV_TIMEOUT);
            46}
                以上do_shutdown是核心函數(shù),調(diào)用SSL_shutdown實(shí)現(xiàn),如果失敗并且返回SSL_ERROR_WANT_READ或SSL_ERROR_WANT_WRITE,就改變讀寫函數(shù)指針為shutdown_handler,shutdown_handler實(shí)現(xiàn)在讀寫事件中繼續(xù)關(guān)閉處理。
            posted on 2014-04-11 17:26 春秋十二月 閱讀(14033) 評(píng)論(0)  編輯 收藏 引用 所屬分類: Network
            中文字幕无码久久久| 久久无码一区二区三区少妇| 久久精品人人做人人爽电影| 欧美熟妇另类久久久久久不卡| 国产成人久久精品一区二区三区| 色婷婷综合久久久久中文一区二区| 91久久精一区二区三区大全| 国产精品无码久久综合网| 亚洲欧美久久久久9999| 精品无码久久久久久尤物| 久久精品国产72国产精福利| 久久夜色精品国产噜噜噜亚洲AV| 久久av高潮av无码av喷吹| 亚洲午夜久久久久久久久电影网| 国产午夜精品久久久久九九电影| 国产精品中文久久久久久久| 久久国产精品久久| 久久久久久久久波多野高潮| 日韩精品国产自在久久现线拍| 久久精品国产99国产精品导航| 久久99精品久久久久久齐齐| 国内精品人妻无码久久久影院| 狠狠色丁香婷婷久久综合五月 | 亚洲一本综合久久| 伊人久久综合成人网| 免费精品久久久久久中文字幕| 欧美亚洲另类久久综合| 99久久久精品免费观看国产| 99久久精品免费看国产一区二区三区| 久久国产香蕉视频| 91久久精品视频| 97久久精品人人做人人爽| 精品久久8x国产免费观看| 久久久久亚洲av无码专区喷水 | 中文字幕久久欲求不满| 久久国产乱子伦精品免费强| 色欲久久久天天天综合网精品| 无码专区久久综合久中文字幕 | 狠狠色丁香婷综合久久| 国内精品久久久久影院优| 精品蜜臀久久久久99网站|