openssl之BIO系列之8---读写出错控制

来源:互联网 发布:数据标准化的公式 编辑:程序博客网 时间:2024/06/05 04:49
读写出错控制
    ---根据openssl doc/crypto/bio/bio_should_retry.pod翻译和自己的理解写成
    
    (作者:DragonKing Mail:wzhah@263.net 发布于:http://gdwzh.126.com之openssl专业论坛)
    
    当BIO_read或BIO_write函数调用出错的时候,BIO本身提供了一组出错原因的诊断函数,他们定义如下(openssl/bio.h):
     #define BIO_should_read(a) ((a)->flags & BIO_FLAGS_READ)
     #define BIO_should_write(a) ((a)->flags & BIO_FLAGS_WRITE)
     #define BIO_should_io_special(a) ((a)->flags & BIO_FLAGS_IO_SPECIAL)
     #define BIO_retry_type(a) ((a)->flags & BIO_FLAGS_RWS)
     #define BIO_should_retry(a) ((a)->flags & BIO_FLAGS_SHOULD_RETRY)
    
     #define BIO_FLAGS_READ 0x01
     #define BIO_FLAGS_WRITE 0x02
     #define BIO_FLAGS_IO_SPECIAL 0x04
     #define BIO_FLAGS_RWS (BIO_FLAGS_READ|BIO_FLAGS_WRITE|BIO_FLAGS_IO_SPECIAL)
     #define BIO_FLAGS_SHOULD_RETRY 0x08
    
     BIO * BIO_get_retry_BIO(BIO *bio, int *reason);
     int BIO_get_retry_reason(BIO *bio);
    因为这些函数是用于决定为什么BIO在读写数据的时候不能读出或写入数据,所以他们一般也是在执行BIO_read或BIO_write操作之后被调用的。
    【BIO_should_retry 】
    如果读写出错的情况是要求程序稍后重试,那么该函数返回true.如果该函数返回false,这时候判定错误情况就要根据BIO的类型和BIO操作的返回值来确定了。比如,如果对socket类型的BIO调用BIO_read操作并且返回值为0,此时BIO_should_retry返回false就说明socket连接已经关闭了。而如果是file类型的BIO出现这样的情况,那说明就是读到文件eof了。有些类型BIO还会提供更多的出错信息,具体情况参见各自的说明。
    如果BIO下层I/O结构是阻塞模式的,那么几乎所有(SSL类型BIO例外)BIO类型都不会返回重试的情况(就是说调用BIO_should_retry不会返回true),因为这时候对下层I/O的调用根本不会进行。所以建议如果你的应用程序能够判定该类型BIO在执行IO操作后不会出现重试的情况时,就不要调用BIO_should_retry函数。file类型BIO就是这样的一个典型例子。
    SSL类型的BIO是上述规则的唯一例外,也就是说,既便在阻塞型的I/O结构中,如果在调用BIO_read的时候发生了握手的过程,它也能会返回重试要求(调用BIO_should_retry返回true)。在这种情况下,应用程序可以立刻重新执行失败的I/O操作,或者在底层的I/O结构中设置为SSL_MODE_AUTO_RETRY,那么就可以避免出现这种失败的情况。
    如果应用程序在非阻塞型BIO中调用IO操作失败后立刻重试,那么可能导致效率很低,因为在数据允许读取或有效之前,调用会重复返回失败结果。所以,正常的应用应该是等到需要的条件满足之后,程序才执行相关的调用,至于具体怎么做,就跟底层的IO结构有关了。例如,如果一个底层IO是一个soket,并且BIO_should_retry返回true,那么可以调用select()来等待数据有效之后再重试IO操作。在一个线程中,可以使用一个select()来处理多个非阻塞型的BIO,不过,这时候执行效率可能出现非常低的情况,比如如果其中一个延时很长的SSL类型BIO在握手的时候就会导致这种情况。
    在阻塞型的IO结构中,对数据的读取操作可能会导致无限期的阻塞,其情况跟系统的IO结构函数有关。我们当然不期望出现这种情况,解决的办法之一是尽量使用非阻塞型的IO结构和使用select函数(或equivalent)来设置等待时间。
    【BIO_should_read】
    该函数返回true如果导致IO操作失败的原因是BIO此时要读数据。
    【BIO_should_write】
    该函数返回true如果导致IO操作失败的原因是BIO此时要写数据。
    【BIO_should_io_special】
    该函数返回true如果导致IO操作失败的原因是特殊的(也就是读写之外的原因)
    【BIO_get_retry_reason】
    返回失败的原因,其代码包括BIO_FLAGS_READ, BIO_FLAGS_WRITE和BIO_FLAGS_IO_SPECIAL。目前的BIO类型只返回其中之一。如果输入的BIO是产生特殊出错情况的BIO,那么该函数返回错误的原因代码,就跟BIO_get_retry_BIO()返回的reason一样。
    【BIO_get_retry_BIO】
    该函数给出特殊情况错误的简短原因,它返回出错的BIO,如果reason不是设置为NULL,它会包含错误代码,错误码的含义以及下一步应该采取的处理措施应该根据发生这种情况下各种BIO的类型而定。
    
原创粉丝点击