● SSL_ERROR_WANT_READ:操作沒完成,需要在下一次讀事件中繼續
● SSL_ERROR_WANT_WRITE:操作沒完成,需要在下一次寫事件中繼續
● SSL_ERROR_ZERO_RETURN:連接正常關閉
● 其它:連接出錯
下面的示例代碼使用了libevent實現IO事件驅動,connection表示普通連接類,假設已經處理好了http數據的邏輯,實現在成員函數handle_read和handle_write內,虛函數recv、send和close分別調用系統的API recv、send和close;ssl_conn_t表示安全連接類,由于只是IO處理不同:收到數據后解密,發送數據前加密。解密后的操作和connection是一樣的,因此ssl_conn_t繼承connection,重寫了recv、send和close,其中close調用了shutdown。
異步握手
當在SSL端口接受到連接時,首先要進行握手,握手成功后才能收發數據,如果握手失敗而且返回前2種錯誤碼,那么要在下一次操作中繼續握手。
1
void ssl_conn_t::empty_handler(short ev)
2
{
3
}
4
5
void ssl_conn_t::handshake_handler(short ev)
6
{
7
handshake();
8
}
9
10
void 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
24
int 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
}
void ssl_conn_t::empty_handler(short ev)2
{3
}4

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

10
void 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

24
int 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
}異步讀寫
對于讀操作失敗,如果返回SSL_ERROR_WANT_WRITE,那么說明要在下一次寫事件中繼續讀數據,因此要改變寫函數指針,使其讀數據,當讀成功后,要還原寫函數針,并激發一次寫事件;對于寫操作失敗,如果返回SSL_ERROR_WANT_READ,那么說明要在下一次讀事件中繼續寫數據,因此要改變讀函數指針,使其寫數據,當寫成功后,要還原讀函數指針,并激發一次讀事件。如果不還原讀或寫函數指針,那么會發生寫或讀混亂;還原后,要激發一次讀或寫事件,這是為了延續IO事件的進行,防止讀寫餓死。
1
ssize_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
30
void ssl_conn_t::write_handler(short ev)
31
{
32
(this->*read_handler_)(EV_WRITE);
33
}
34
35
ssize_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
64
void ssl_conn_t::read_handler(short ev)
65
{
66
(this->*write_handler_)(EV_READ);
67
}
ssize_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

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

35
ssize_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

64
void ssl_conn_t::read_handler(short ev)65
{66
(this->*write_handler_)(EV_READ);67
}異步關閉
當握手或讀寫因連接關閉或出錯而失敗時,就要關閉連接了,如果失敗并且返回SSL_ERROR_WANT_READ或SSL_ERROR_WANT_WRITE,那么要在下一次讀或寫事件中繼續關閉。在這里,為了收到對方發送的協議退出包而完全退出,等待30秒再關閉,如果超時就直接關閉。
1
void ssl_conn_t::shutdown(bool is_timeout/*=false*/)
2
{
3
if (do_shutdown(is_timeout) != OP_AGAIN)
4
delete this;
5
}
6
7
int 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
43
void ssl_conn_t::shutdown_handler(short ev)
44
{
45
shutdown(ev&EV_TIMEOUT);
46
}
void ssl_conn_t::shutdown(bool is_timeout/*=false*/)2
{3
if (do_shutdown(is_timeout) != OP_AGAIN)4
delete this;5
}6

7
int 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

43
void ssl_conn_t::shutdown_handler(short ev)44
{45
shutdown(ev&EV_TIMEOUT);46
}



