OpenSSL 1.1 result in error: variable has initializer but incomplete type static BIO_METHOD
Vincent Li
vincent.mc.li at gmail.com
Wed Jul 1 17:44:03 UTC 2020
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
More information about the openssl-users
mailing list