diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3c13531e8..760d60faf 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -60,6 +60,11 @@ include_directories( find_package(re CONFIG REQUIRED HINTS ../cmake) +if(CMAKE_C_COMPILER_ID MATCHES "Clang" OR CMAKE_C_COMPILER_ID MATCHES "GNU") + set(HAVE_WRAP TRUE) + list(APPEND RE_DEFINITIONS HAVE_WRAP) +endif() + ############################################################################## # # Source/Header section @@ -143,6 +148,14 @@ set(SRCS websock.c ) +if(HAVE_WRAP) + list(APPEND SRCS + wrap/wrap.c + wrap/epoll.c + wrap/getaddrinfo.c + ) +endif() + if(USE_OPENSSL) list(APPEND SRCS tls.c @@ -175,6 +188,16 @@ set_property(TARGET ${PROJECT_NAME} PROPERTY ENABLE_EXPORTS 1) target_link_libraries(${PROJECT_NAME} PRIVATE ${LINKLIBS}) target_compile_definitions(${PROJECT_NAME} PRIVATE ${RE_DEFINITIONS}) +if(HAVE_WRAP) + target_link_options(${PROJECT_NAME} PRIVATE + -Wl, + --wrap=epoll_create, + --wrap=epoll_ctl, + --wrap=getaddrinfo, + --wrap=freeaddrinfo + ) +endif() + if(USE_OPENSSL) target_include_directories(${PROJECT_NAME} PRIVATE ${OPENSSL_INCLUDE_DIR}) endif() diff --git a/test/test.h b/test/test.h index 5f92e98d7..04f4f0f63 100644 --- a/test/test.h +++ b/test/test.h @@ -547,3 +547,12 @@ int dns_server_add_srv(struct dns_server *srv, const char *name, uint16_t pri, uint16_t weight, uint16_t port, const char *target); void dns_server_flush(struct dns_server *srv); + + +/* + * Wrap functions + */ +int wrap_will_return_int(const char *func, int ret); +int wrap_will_return_data(const char *func, void *data); +int wrap_return_int(const char *func, int *ret); +void *wrap_return_data(const char *func); diff --git a/test/wrap/epoll.c b/test/wrap/epoll.c new file mode 100644 index 000000000..ea775a40a --- /dev/null +++ b/test/wrap/epoll.c @@ -0,0 +1,30 @@ +#include + +#include +#include "test.h" + + +int __wrap_epoll_create(int size); +int __real_epoll_create(int size); + +int __wrap_epoll_create(int size) +{ + int ret; + + int err = wrap_return_int("epoll_create", &ret); + + return err ? __real_epoll_create(size) : ret; +} + + +int __wrap_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); +int __real_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); + +int __wrap_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) +{ + int ret; + + int err = wrap_return_int("epoll_create", &ret); + + return err ? __real_epoll_ctl(epfd, op, fd, event) : ret; +} diff --git a/test/wrap/getaddrinfo.c b/test/wrap/getaddrinfo.c new file mode 100644 index 000000000..41b4e4511 --- /dev/null +++ b/test/wrap/getaddrinfo.c @@ -0,0 +1,26 @@ +#include + +#include +#include "test.h" + + +int __wrap_getaddrinfo(const char *restrict node, const char *restrict service, + const struct addrinfo *restrict hints, + struct addrinfo **restrict res); +int __real_getaddrinfo(const char *restrict node, const char *restrict service, + const struct addrinfo *restrict hints, + struct addrinfo **restrict res); +int __wrap_getaddrinfo(const char *restrict node, const char *restrict service, + const struct addrinfo *restrict hints, + struct addrinfo **restrict res) +{ + return __real_getaddrinfo(node, service, hints, res); +} + + +void __wrap_freeaddrinfo(struct addrinfo *res); +void __real_freeaddrinfo(struct addrinfo *res); +void __wrap_freeaddrinfo(struct addrinfo *res) +{ + __real_freeaddrinfo(res); +} diff --git a/test/wrap/wrap.c b/test/wrap/wrap.c new file mode 100644 index 000000000..e4990bde1 --- /dev/null +++ b/test/wrap/wrap.c @@ -0,0 +1,129 @@ +#include +#include "test.h" + +enum wrap_type { + WRAP_INT, + WRAP_DATA +}; + +struct wrap_entry { + struct le le; + char func[64]; + enum wrap_type type; + union { + int ret_int; + void *ret_data; + } u; +}; + +static struct list wrapl = LIST_INIT; + + +static void entry_destruct(void *arg) +{ + struct wrap_entry *e = arg; + list_unlink(&e->le); +} + + +static struct wrap_entry *wrap_entry_alloc(const char *func) +{ + struct wrap_entry *e; + + e = mem_alloc(sizeof(struct wrap_entry), entry_destruct); + if (!e) + return NULL; + + str_ncpy(e->func, func, sizeof(e->func)); + + list_append(&wrapl, &e->le, e); + + return e; +} + + +int wrap_will_return_int(const char *func, int ret) +{ + struct wrap_entry *e; + + if (!func) + return EINVAL; + + e = wrap_entry_alloc(func); + if (!e) + return ENOMEM; + + e->type = WRAP_INT; + e->u.ret_int = ret; + + return 0; +} + + +int wrap_will_return_data(const char *func, void *data) +{ + struct wrap_entry *e; + + if (!func) + return EINVAL; + + e = wrap_entry_alloc(func); + if (!e) + return ENOMEM; + + e->type = WRAP_DATA; + e->u.ret_data = data; + + return 0; +} + + +int wrap_return_int(const char *func, int *ret) +{ + struct le *le; + + if (!func) + return EINVAL; + + LIST_FOREACH(&wrapl, le) + { + struct wrap_entry *e = le->data; + + if (e->type != WRAP_INT) + continue; + + if (0 == str_casecmp(e->func, func)) { + *ret = e->u.ret_int; + mem_deref(e); + return 0; + } + } + + return ENODATA; +} + + +void *wrap_return_data(const char *func) +{ + struct le *le; + void *data; + + if (!func) + return NULL; + + LIST_FOREACH(&wrapl, le) + { + struct wrap_entry *e = le->data; + + if (e->type != WRAP_DATA) + continue; + + if (0 == str_casecmp(e->func, func)) { + data = e->u.ret_data; + mem_deref(e); + return data; + } + } + + return NULL; +}