OpenSSL 1.1 result in error: variable has initializer but incomplete type static BIO_METHOD

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

OpenSSL 1.1 result in error: variable has initializer but incomplete type static BIO_METHOD

Vincent Li

Hi,

I am running apache bench (ab) and ported it with OpenSSL 1.0 support on top of mTCP support

https://github.com/vincentmli/mtcp/commit/642835f786aa642ea0f20fe8db9b09054639453a#diff-02f7a72f514e6e0543e832d37450c251

but it breaks after I upgraded OpenSSL 1.0 to OpenSSL 1.1, I found there
are quite a few projects having same problems including libevent, libevent
has the fix in https://github.com/libevent/libevent/commit/3e9e0a0d46e4508e8782ec3787c6d86bab63046d

so I borrowed the fix from libevent and applied the code fix below:

```
#include <openssl/bio.h>
#include "openssl-compat.h"
#define get_last_socket_error() errno
#define clear_socket_error()    errno=0
/* clone of openssl crypto/bio/bss_sock.c */

#ifdef HAVE_MTCP

static int mtcp_sock_write(BIO *h, const char *buf, int num);
static int mtcp_sock_read(BIO *h, char *buf, int size);
static int mtcp_sock_puts(BIO *h, const char *str);
static long mtcp_sock_ctrl(BIO *h, int cmd, long arg1, void *arg2);
static int mtcp_sock_new(BIO *h);
static int mtcp_sock_free(BIO *data);
int BIO_mtcp_sock_should_retry(int s);

/*
static BIO_METHOD mtcp_methods_sockp = {
    BIO_TYPE_SOCKET,
    "socket",
    mtcp_sock_write,
    mtcp_sock_read,
    mtcp_sock_puts,
    NULL,                      
    mtcp_sock_ctrl,
    mtcp_sock_new,
    mtcp_sock_free,
    NULL,
};


BIO_METHOD *BIO_mtcp_s_socket(void)
{
    return (&mtcp_methods_sockp);
}
*/

static BIO_METHOD *mtcp_methods_sockp;

static BIO_METHOD *
BIO_mtcp_s_socket(void)
{
        if (mtcp_methods_sockp == NULL) {
                mtcp_methods_sockp = BIO_meth_new(BIO_TYPE_SOCKET,
"socket");
                if (mtcp_methods_sockp == NULL)
                        return NULL;
                BIO_meth_set_write(mtcp_methods_sockp, mtcp_sock_write);
                BIO_meth_set_read(mtcp_methods_sockp, mtcp_sock_read);
                BIO_meth_set_puts(mtcp_methods_sockp, mtcp_sock_puts);
                BIO_meth_set_ctrl(mtcp_methods_sockp, mtcp_sock_ctrl);
                BIO_meth_set_create(mtcp_methods_sockp, mtcp_sock_new);
                BIO_meth_set_destroy(mtcp_methods_sockp, mtcp_sock_free);
        }
        return mtcp_methods_sockp;
}

/*
BIO *BIO_mtcp_new_socket(mctx_t mctx, int fd, int close_flag)
{
    BIO *ret;

    ret = BIO_new(BIO_mtcp_s_socket());
    if (ret == NULL)
        return (NULL);
    BIO_set_fd(ret, fd, close_flag);
    ret->ptr = mctx;
    return (ret);
}
*/


BIO *BIO_mtcp_new_socket(mctx_t mctx, int fd, int close_flag)
{
    BIO *ret;

    if(!fd)
        return NULL;
    ret = BIO_new(BIO_mtcp_s_socket());
    if (ret == NULL)
        return (NULL);
    BIO_set_init(ret, 1);
    BIO_set_fd(ret, fd, close_flag);
    BIO_set_data(ret, mctx);
    return (ret);
}

/*
static int mtcp_sock_new(BIO *bi)
{
    bi->init = 0;
    bi->num = 0;
    bi->ptr = NULL;
    bi->flags = 0;
    return (1);
}
*/

static int mtcp_sock_new(BIO *bi)
{
    BIO_set_init(bi, 0);
    BIO_set_num(bi, 0);
    BIO_set_data(bi, NULL);
    BIO_set_flags(bi, 0);
    return (1);
}

/*
static int mtcp_sock_free(BIO *a)
{
    if (a == NULL)
        return (0);
    mctx_t mctx = (mctx_t)a->ptr;
    mtcp_close(mctx, a->num);

    return (1);
}
*/

static int mtcp_sock_free(BIO *a)
{
    if (a == NULL)
        return (0);
    mctx_t mctx = (mctx_t)BIO_get_data(a);
    mtcp_close(mctx, BIO_get_num(a));

    return (1);
}


/*
static int mtcp_sock_read(BIO *b, char *out, int outl)
{
    int ret = 0;
    mctx_t mctx = (mctx_t)b->ptr;

    if (out != NULL) {
        clear_socket_error();
        //ret = readsocket(b->num, out, outl);
        ret = mtcp_read(mctx, b->num, out, outl);
        BIO_clear_retry_flags(b);
        if (ret <= 0) {
            if (BIO_mtcp_sock_should_retry(ret))
                BIO_set_retry_read(b);
        }
    }
    return (ret);
}
*/

static int mtcp_sock_read(BIO *b, char *out, int outl)
{
    int ret = 0;
    mctx_t mctx = (mctx_t)BIO_get_data(b);

    if (out != NULL) {
        clear_socket_error();
        //ret = readsocket(b->num, out, outl);
        ret = mtcp_read(mctx, BIO_get_num(b), out, outl);
        BIO_clear_retry_flags(b);
        if (ret <= 0) {
            if (BIO_mtcp_sock_should_retry(ret))
                BIO_set_retry_read(b);
        }
    }
    return (ret);
}

/*
static int mtcp_sock_write(BIO *b, const char *in, int inl)
{
    int ret;
    mctx_t mctx = (mctx_t)b->ptr;

    clear_socket_error();
    //ret = writesocket(b->num, in, inl);
    ret = mtcp_write(mctx, b->num, in, inl);
    BIO_clear_retry_flags(b);
    if (ret <= 0) {
        if (BIO_mtcp_sock_should_retry(ret))
            BIO_set_retry_write(b);
    }
    return (ret);
}
*/

static int mtcp_sock_write(BIO *b, const char *in, int inl)
{
    int ret;
    mctx_t mctx = (mctx_t)BIO_get_data(b);

    clear_socket_error();
    //ret = writesocket(b->num, in, inl);
    ret = mtcp_write(mctx, BIO_get_num(b), in, inl);
    BIO_clear_retry_flags(b);
    if (ret <= 0) {
        if (BIO_mtcp_sock_should_retry(ret))
            BIO_set_retry_write(b);
    }
    return (ret);
}

/*
static long mtcp_sock_ctrl(BIO *b, int cmd, long num, void *ptr)
{
    long ret = 1;
    int *ip;

    switch (cmd) {
    case BIO_C_SET_FD:
        mtcp_sock_free(b);
        b->num = *((int *)ptr);
        b->shutdown = (int)num;
        b->init = 1;
        break;
    case BIO_C_GET_FD:
        if (b->init) {
            ip = (int *)ptr;
            if (ip != NULL)
                *ip = b->num;
            ret = b->num;
        } else
            ret = -1;
        break;
    case BIO_CTRL_GET_CLOSE:
        ret = b->shutdown;
        break;
    case BIO_CTRL_SET_CLOSE:
        b->shutdown = (int)num;
        break;
    case BIO_CTRL_DUP:
    case BIO_CTRL_FLUSH:
        ret = 1;
        break;
    default:
        ret = 0;
        break;
    }
    return (ret);
}
*/

static long mtcp_sock_ctrl(BIO *b, int cmd, long num, void *ptr)
{
    long ret = 1;
    int *ip;

    switch (cmd) {
    case BIO_C_SET_FD:
        mtcp_sock_free(b);
        BIO_set_num(b, *((int *)ptr));
        BIO_set_shutdown(b, (int)num);
        BIO_set_init(b, 1);
        break;
    case BIO_C_GET_FD:
        if (BIO_get_init(b)) {
            ip = (int *)ptr;
            if (ip != NULL)
                *ip = BIO_get_num(b);
            ret = BIO_get_num(b);
        } else
            ret = -1;
        break;
    case BIO_CTRL_GET_CLOSE:
        ret = BIO_get_shutdown(b);
        break;
    case BIO_CTRL_SET_CLOSE:
        BIO_set_shutdown(b, (int)num);
        break;
    case BIO_CTRL_DUP:
    case BIO_CTRL_FLUSH:
        ret = 1;
        break;
    default:
        ret = 0;
        break;
    }
    return (ret);
}

```

here is the openssl-compat.h

```
#ifndef OPENSSL_COMPAT_H
#define OPENSSL_COMPAT_H

#include <openssl/bio.h>

#if (OPENSSL_VERSION_NUMBER < 0x10100000L)

static inline BIO_METHOD *BIO_meth_new(int type, const char *name)
{
        BIO_METHOD *biom = calloc(1, sizeof(BIO_METHOD));

        if (biom != NULL) {
                biom->type = type;
                biom->name = name;
        }
        return biom;
}

#define BIO_meth_set_write(b, f) (b)->bwrite = (f)
#define BIO_meth_set_read(b, f) (b)->bread = (f)
#define BIO_meth_set_puts(b, f) (b)->bputs = (f)
#define BIO_meth_set_ctrl(b, f) (b)->ctrl = (f)
#define BIO_meth_set_create(b, f) (b)->create = (f)
#define BIO_meth_set_destroy(b, f) (b)->destroy = (f)

#define BIO_set_init(b, val) (b)->init = (val)
#define BIO_set_data(b, val) (b)->ptr = (val)
#define BIO_set_shutdown(b, val) (b)->shutdown = (val)
#define BIO_set_num(b, val) (b)->num = (val)
#define BIO_set_flags(b, val) (b)->flags = (val)
#define BIO_get_init(b) (b)->init
#define BIO_get_data(b) (b)->ptr
#define BIO_get_shutdown(b) (b)->shutdown
#define BIO_get_num(b) (b)->num
#define BIO_get_flags(b) (b)->flags

#define TLS_method SSLv23_method

#endif /* (OPENSSL_VERSION_NUMBER < 0x10100000L) */

#endif /* OPENSSL_COMPAT_H */

```

but I got compiling error

```
make[2]: Entering directory '/usr/src/mtcp/apps/apache_benchmark/support'
/usr/src/mtcp/apps/apache_benchmark/srclib/apr/libtool --silent
--mode=compile gcc -g -O2 -pthread -I/usr/src/mtcp/mtcp/lib/
-I/usr/src/mtcp/mtcp/src/include/ -DMULTI_THREADED
-I/usr/src/mtcp/mtcp/lib/ -I/usr/src/mtcp/mtcp/src/include/
-DMULTI_THREADED    -DLINUX -D_REENTRANT -D_GNU_SOURCE    
-I/usr/src/mtcp/apps/apache_benchmark/srclib/pcre -I.
-I/usr/src/mtcp/apps/apache_benchmark/os/unix
-I/usr/src/mtcp/apps/apache_benchmark/include
-I/usr/src/mtcp/apps/apache_benchmark/srclib/apr/include
-I/usr/src/mtcp/apps/apache_benchmark/srclib/apr-util/include
-I/usr/src/mtcp/apps/apache_benchmark/srclib/apr-util/xml/expat/lib
-I/usr/lib/include -I/usr/src/mtcp/apps/apache_benchmark/modules/ssl  
-prefer-non-pic -static -c ab.c && touch ab.lo
ab.c: In function ‘mtcp_sock_new’:
ab.c:547:5: warning: implicit declaration of function ‘BIO_set_num’; did
you mean ‘BIO_set_next’? [-Wimplicit-function-declaration]
     BIO_set_num(bi, 0);
     ^~~~~~~~~~~
     BIO_set_next
ab.c: In function ‘mtcp_sock_free’:
ab.c:570:22: warning: implicit declaration of function ‘BIO_get_num’; did
you mean ‘BIO_get_init’? [-Wimplicit-function-declaration]
     mtcp_close(mctx, BIO_get_num(a));
                      ^~~~~~~~~~~
                      BIO_get_init
..........CUT......
/usr/src/mtcp/apps/apache_benchmark/support/ab.c:547: undefined reference
to `BIO_set_num'
.libs/ab.o: In function `mtcp_sock_free':
/usr/src/mtcp/apps/apache_benchmark/support/ab.c:570: undefined reference
to `BIO_get_num'
.libs/ab.o: In function `mtcp_sock_ctrl':
/usr/src/mtcp/apps/apache_benchmark/support/ab.c:703: undefined reference
to `BIO_get_num'
/usr/src/mtcp/apps/apache_benchmark/support/ab.c:704: undefined reference
to `BIO_get_num'
/usr/src/mtcp/apps/apache_benchmark/support/ab.c:695: undefined reference
to `BIO_set_num'
.libs/ab.o: In function `mtcp_sock_read':
/usr/src/mtcp/apps/apache_benchmark/support/ab.c:603: undefined reference
to `BIO_get_num'
.libs/ab.o: In function `mtcp_sock_write':
/usr/src/mtcp/apps/apache_benchmark/support/ab.c:638: undefined reference
to `BIO_get_num'
.libs/ab.o: In function `main':
/usr/src/mtcp/apps/apache_benchmark/support/ab.c:2916: undefined reference
to `SSLv3_client_method'
/usr/src/mtcp/apps/apache_benchmark/support/ab.c:2913: undefined reference
to `SSLv2_client_method'
/usr/src/mtcp/apps/apache_benchmark/support/ab.c:2978: undefined reference
to `CRYPTO_malloc_init'
collect2: error: ld returned 1 exit status
Makefile:38: recipe for target 'ab' failed
make[2]: *** [ab] Error 1

```

Since I defined BIO_set/get_init/data/shutdown/num in openssl-compat.h,
why it only shows undefined reference to `BIO_set/set_num', not others? I
am confused

Reply | Threaded
Open this post in threaded view
|

Re: OpenSSL 1.1 result in error: variable has initializer but incomplete type static BIO_METHOD

Vincent Li


On Wed, 1 Jul 2020, Vincent Li wrote:

>
> Hi,
>
> I am running apache bench (ab) and ported it with OpenSSL 1.0 support on top of mTCP support
>
> https://github.com/vincentmli/mtcp/commit/642835f786aa642ea0f20fe8db9b09054639453a#diff-02f7a72f514e6e0543e832d37450c251
>
> but it breaks after I upgraded OpenSSL 1.0 to OpenSSL 1.1, I found there
> are quite a few projects having same problems including libevent, libevent
> has the fix in https://github.com/libevent/libevent/commit/3e9e0a0d46e4508e8782ec3787c6d86bab63046d
>
> so I borrowed the fix from libevent and applied the code fix below:
>
> ```
> #include <openssl/bio.h>
> #include "openssl-compat.h"
> #define get_last_socket_error() errno
> #define clear_socket_error()    errno=0
> /* clone of openssl crypto/bio/bss_sock.c */
>
> #ifdef HAVE_MTCP
>
> static int mtcp_sock_write(BIO *h, const char *buf, int num);
> static int mtcp_sock_read(BIO *h, char *buf, int size);
> static int mtcp_sock_puts(BIO *h, const char *str);
> static long mtcp_sock_ctrl(BIO *h, int cmd, long arg1, void *arg2);
> static int mtcp_sock_new(BIO *h);
> static int mtcp_sock_free(BIO *data);
> int BIO_mtcp_sock_should_retry(int s);
.........SNIP.........

>
> static long mtcp_sock_ctrl(BIO *b, int cmd, long num, void *ptr)
> {
>     long ret = 1;
>     int *ip;
>
>     switch (cmd) {
>     case BIO_C_SET_FD:
>         mtcp_sock_free(b);
>         BIO_set_num(b, *((int *)ptr));
>         BIO_set_shutdown(b, (int)num);
>         BIO_set_init(b, 1);
>         break;
>     case BIO_C_GET_FD:
>         if (BIO_get_init(b)) {
>             ip = (int *)ptr;
>             if (ip != NULL)
>                 *ip = BIO_get_num(b);
>             ret = BIO_get_num(b);
>         } else
>             ret = -1;
>         break;
>     case BIO_CTRL_GET_CLOSE:
>         ret = BIO_get_shutdown(b);
>         break;
>     case BIO_CTRL_SET_CLOSE:
>         BIO_set_shutdown(b, (int)num);
>         break;
>     case BIO_CTRL_DUP:
>     case BIO_CTRL_FLUSH:
>         ret = 1;
>         break;
>     default:
>         ret = 0;
>         break;
>     }
>     return (ret);
> }

I found http://vega.pgw.jp/~kabe/vsd/migrate2openssl-1.1.html which says:

"bio->num (file descripter) could be set by BIO_set_fd(), but since this
callbacks the routine set by BIO_meth_set_ctrl(biom, BioCtrl), beware of
infinite loops. Recommend to not touch bio->num member and leave it
alone."

so I used BIO_set/get_fd() to work with the bio->num, it compiles ok with
some warnings, but it appears I hit the infinite loops and core dump:

root@vli-lab:/usr/src/mtcp/apps/apache_benchmark/support# cp .libs/ab .
root@vli-lab:/usr/src/mtcp/apps/apache_benchmark/support# gdb --args  ab -N 4 -c 4 -n 160 https://10.2.1.63/
GNU gdb (Ubuntu 8.1-0ubuntu3.2) 8.1.0.20180409-git
...........SNIP............
Checking link status..done
Port 0 Link Up - speed 10000 Mbps - full-duplex
Benchmarking 10.2.1.63 (be patient)
[New Thread 0x7fdff19fb700 (LWP 1510)]
CPU0 connecting to port 443
[New Thread 0x7fdff11fa700 (LWP 1511)]
[New Thread 0x7fdff09f9700 (LWP 1512)]
CPU1 connecting to port 443
[New Thread 0x7fdfea6fe700 (LWP 1513)]
CPU2 connecting to port 443
[New Thread 0x7fdfd7fff700 (LWP 1514)]
CPU3 connecting to port 443
CPU 0: initialization finished.
[mtcp_create_context:1359] CPU 0 is now the master thread.
[CPU 0] dpdk0 flows:      0, RX:       0(pps) (err:     0),  0.00(Gbps),
TX:       0(pps),  0.00(Gbps)
[ ALL ] dpdk0 flows:      0, RX:       0(pps) (err:     0),  0.00(Gbps),
TX:       0(pps),  0.00(Gbps)

Thread 8 "ab" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fdff19fb700 (LWP 1510)]
0x00005555555dd3cd in mtcp_sock_ctrl (b=0x7fdfe4003dd0, cmd=105, num=0,
ptr=0x560af680, close_flag=1443559040) at ab.c:692
692    switch (cmd) {
(gdb) bt
#0  0x00005555555dd3cd in mtcp_sock_ctrl (b=0x7fdfe4003dd0, cmd=105,
num=0, ptr=0x560af680, close_flag=1443559040) at ab.c:692
#1  0x00007ffff6474949 in BIO_ctrl () from
/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
#2  0x00005555555dd3fb in mtcp_sock_ctrl (b=0x7fdfe4003dd0, cmd=<optimized
out>, num=<optimized out>, ptr=0x560af680,
    close_flag=1443559040) at ab.c:703
#3  0x00007ffff6474949 in BIO_ctrl () from
/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
#4  0x00005555555dd3fb in mtcp_sock_ctrl (b=0x7fdfe4003dd0, cmd=<optimized
out>, num=<optimized out>, ptr=0x560af680,
    close_flag=1443559040) at ab.c:703
#5  0x00007ffff6474949 in BIO_ctrl () from
/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
#6  0x00005555555dd3fb in mtcp_sock_ctrl (b=0x7fdfe4003dd0, cmd=<optimized
out>, num=<optimized out>, ptr=0x560af680,
    close_flag=1443559040) at ab.c:703
....loop continues....

How do I avoid the loops?

here is the changed code:

#ifdef USE_SSL

#ifndef OPENSSL_NO_SOCK

#include <openssl/bio.h>
#include "openssl-compat.h"
#define get_last_socket_error() errno
#define clear_socket_error()    errno=0
/* clone of openssl crypto/bio/bss_sock.c */

#ifdef HAVE_MTCP

static int mtcp_sock_write(BIO *h, const char *buf, int num, int
close_flag);
static int mtcp_sock_read(BIO *h, char *buf, int size, int close_flag);
static int mtcp_sock_puts(BIO *h, const char *str, int close_flag);
static long mtcp_sock_ctrl(BIO *h, int cmd, long arg1, void *arg2, int
close_flag);
static int mtcp_sock_new(BIO *h);
static int mtcp_sock_free(BIO *data, int close_flag);
int BIO_mtcp_sock_should_retry(int s);

static BIO_METHOD *mtcp_methods_sockp;

static BIO_METHOD *
BIO_mtcp_s_socket(void)
{
        if (mtcp_methods_sockp == NULL) {
                mtcp_methods_sockp = BIO_meth_new(BIO_TYPE_SOCKET,
"socket");
                if (mtcp_methods_sockp == NULL)
                        return NULL;
                BIO_meth_set_write(mtcp_methods_sockp, mtcp_sock_write);
                BIO_meth_set_read(mtcp_methods_sockp, mtcp_sock_read);
                BIO_meth_set_puts(mtcp_methods_sockp, mtcp_sock_puts);
                BIO_meth_set_ctrl(mtcp_methods_sockp, mtcp_sock_ctrl);
                BIO_meth_set_create(mtcp_methods_sockp, mtcp_sock_new);
                BIO_meth_set_destroy(mtcp_methods_sockp, mtcp_sock_free);
        }
        return mtcp_methods_sockp;
}

BIO *BIO_mtcp_new_socket(mctx_t mctx, int fd, int close_flag)
{
    BIO *ret;

    if(!fd)
        return NULL;
    ret = BIO_new(BIO_mtcp_s_socket());
    if (ret == NULL)
        return (NULL);
    BIO_set_init(ret, 1);
    BIO_set_fd(ret, fd, close_flag);
    BIO_set_data(ret, mctx);
    return (ret);
}

static int mtcp_sock_new(BIO *bi)
{
    BIO_set_init(bi, 0);
   // BIO_set_fd(bi, fd, close_flag)
    BIO_set_data(bi, NULL);
    BIO_set_flags(bi, 0);
    return (1);
}
static int mtcp_sock_free(BIO *a, int close_flag)
{
    if (a == NULL)
        return (0);
    mctx_t mctx = (mctx_t)BIO_get_data(a);
    mtcp_close(mctx, BIO_get_fd(a, close_flag));

    return (1);
}

static int mtcp_sock_read(BIO *b, char *out, int outl, int close_flag)
{
    int ret = 0;
    mctx_t mctx = (mctx_t)BIO_get_data(b);

    if (out != NULL) {
        clear_socket_error();
        //ret = readsocket(b->num, out, outl);
        ret = mtcp_read(mctx, BIO_get_fd(b, close_flag), out, outl);
        BIO_clear_retry_flags(b);
        if (ret <= 0) {
            if (BIO_mtcp_sock_should_retry(ret))
                BIO_set_retry_read(b);
        }
    }
    return (ret);
}

static int mtcp_sock_write(BIO *b, const char *in, int inl, int
close_flag)
{
    int ret;
    mctx_t mctx = (mctx_t)BIO_get_data(b);

    clear_socket_error();
    //ret = writesocket(b->num, in, inl);
    ret = mtcp_write(mctx, BIO_get_fd(b, close_flag), in, inl);
    BIO_clear_retry_flags(b);
    if (ret <= 0) {
        if (BIO_mtcp_sock_should_retry(ret))
            BIO_set_retry_write(b);
    }
    return (ret);
}


static long mtcp_sock_ctrl(BIO *b, int cmd, long num, void *ptr, int
close_flag)
{
    long ret = 1;
    int *ip;

    switch (cmd) {
    case BIO_C_SET_FD:
        mtcp_sock_free(b, close_flag);
        BIO_set_fd(b, *((int *)ptr), close_flag);
        BIO_set_shutdown(b, (int)num);
        BIO_set_init(b, 1);
        break;
    case BIO_C_GET_FD:
        if (BIO_get_init(b)) {
            ip = (int *)ptr;
            if (ip != NULL)
                *ip = BIO_get_fd(b, close_flag);
            ret = BIO_get_fd(b, close_flag);
        } else
            ret = -1;
        break;
    case BIO_CTRL_GET_CLOSE:
        ret = BIO_get_shutdown(b);
        break;
    case BIO_CTRL_SET_CLOSE:
        BIO_set_shutdown(b, (int)num);
        break;
    case BIO_CTRL_DUP:
    case BIO_CTRL_FLUSH:
        ret = 1;
        break;
    default:
        ret = 0;
        break;
    }
    return (ret);
}

static int mtcp_sock_puts(BIO *bp, const char *str, int close_flag)
{
    int n, ret;

    n = strlen(str);
    ret = mtcp_sock_write(bp, str, n, close_flag);
    return (ret);
}