【问题标题】:How to get the underlying socket read buffer size?如何获取底层套接字读取缓冲区大小?
【发布时间】:2014-05-01 12:36:07
【问题描述】:

有一个原始套接字的api:

int sz;
ioctlsocket(sock, FIONREAD, &sz); 
::recv(sock, buff, sz, 0);

ioctlsocket可以用来获取传入的缓冲区大小,但是如何用openssl获取:

int sz = what?
SSL_read(pSSL, buff, sz);

【问题讨论】:

    标签: c openssl


    【解决方案1】:

    但是如何使用 openssl 获取 [传入缓冲区大小]?

    OpenSSL 使用BIOs。写缓冲区有一个BIO_get_write_buf_size,但读缓冲区没有相应的控制。您可以使用BIO_set_read_buffer_size 设置读取缓冲区大小。但我相信这会为BIO 设置缓冲区,而不是套接字上的 I/O 缓冲区。请参阅crypto/bio/bss_bio.c 中的struct bio_bio_st 以及BIO_f_buffer(3)BIO_s_bio(3) 中的文档。

    您应该能够在BIO 上调用BIO_get_fd 以获取底层套接字,然后使用ioctlioctlsocket。您可以在SSL* 中找到BIO。 OpenSSL 方便地具有SSL_get_rbioSSL_get_wbio。来自ssl/ssl.h

    struct ssl_st
        {
        /* protocol version
         * (one of SSL2_VERSION, SSL3_VERSION, TLS1_VERSION, DTLS1_VERSION)
         */
        int version;
        int type; /* SSL_ST_CONNECT or SSL_ST_ACCEPT */
    
        const SSL_METHOD *method; /* SSLv3 */
    
        /* There are 2 BIO's even though they are normally both the
         * same.  This is so data can be read and written to different
         * handlers */
    
    #ifndef OPENSSL_NO_BIO
        BIO *rbio; /* used by SSL_read */
        BIO *wbio; /* used by SSL_write */
        BIO *bbio; /* used during session-id reuse to concatenate messages */
    #else
        char *rbio; /* used by SSL_read */
        char *wbio; /* used by SSL_write */
        char *bbio;
    #endif
        /* This holds a variable that indicates what we were doing
         * when a 0 or -1 is returned.  This is needed for
         * non-blocking IO so we know what request needs re-doing when
         * in SSL_accept or SSL_connect */
        int rwstate;
        ...
    };
    

    【讨论】:

      【解决方案2】:

      感谢 jww 提供代码和标题更正。

      这是我的代码

      // create ssl connection
      ctx = SSL_CTX_new(SSLv23_client_method()); 
      pSSL = SSL_new(ctx);
      sbio = BIO_new_socket(raw_socket, BIO_NOCLOSE); 
      SSL_set_bio(pSSL, sbio, sbio); 
      SSL_set_fd(pSSL, raw_socket);
      SSL_connect(pSSL)
      
      // send
      SSL_write(pSSL, s.c_str(), s.length());
      
      // receive
      int sock_fd;
      int r = BIO_get_fd(sbio, &sock_fd); // <------------------
      cout << r << endl; // output -2
      

      甚至使用 BIO_new_socket 和 SSL_set_fd 中使用的 raw_socket

      ulong sz = 0;
      while(sz == 0) { // <--------- it loops forever, even server echoes data
          if(ioctlsocket(raw_socket, FIONREAD, &sz) != 0) {
              throw "get_recv_size";
          }
          Sleep(0);
      }
      

      raw_socket和BIO中使用的底层socket是不同的吗?

      【讨论】:

        【解决方案3】:

        OP 本质上是问“传递给 SSL_read 的缓冲区应该有多大?”以 jww 的回答为基础,并且 - 这是关键 - 如果您不介意使用可能在未来版本的 OpenSSL 中更改的内容,那么很容易获得读取缓冲区大小。

        注意:这是基于 openssl 1.0.2e

        使用 SSL_get_rbio() 获取 jww 描述的 BIO。 BIO 大小存储在 BIO 内的 BIO_F_BUFFER_CTX 中。这可以在文件 crypto/bio/bf_cuff.c 中看到:

        static int buffer_new(BIO *bi)
        {
            BIO_F_BUFFER_CTX *ctx;
        
            ctx = (BIO_F_BUFFER_CTX *)OPENSSL_malloc(sizeof(BIO_F_BUFFER_CTX));
            if (ctx == NULL)
                return (0);
            ctx->ibuf = (char *)OPENSSL_malloc(DEFAULT_BUFFER_SIZE);
            if (ctx->ibuf == NULL) {
                OPENSSL_free(ctx);
                return (0);
            }
            ctx->obuf = (char *)OPENSSL_malloc(DEFAULT_BUFFER_SIZE);
            if (ctx->obuf == NULL) {
                OPENSSL_free(ctx->ibuf);
                OPENSSL_free(ctx);
                return (0);
            }
            ctx->ibuf_size = DEFAULT_BUFFER_SIZE;
            ctx->obuf_size = DEFAULT_BUFFER_SIZE;
            ctx->ibuf_len = 0;
            ctx->ibuf_off = 0;
            ctx->obuf_len = 0;
            ctx->obuf_off = 0;
        
            bi->init = 1;
            bi->ptr = (char *)ctx;
            bi->flags = 0;
            return (1);
        }
        

        获取读取缓冲区大小可以通过以下方式完成:

        ((BIO_F_BUFFER_CTX*)bio->ptr)->ibuf_size;
        

        其中bio 是一个代表要查询的BIO 的变量。 ptr 变量需要从 char* 中回滚。

        请注意,这适用于任何 BIO,例如从 BIO_new_ssl_connect( ctx ) 返回的那个,等等。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-09-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多