Reimplement TCP Server with libuv and add configure/meson flags (#11403)

This commit is contained in:
Florian Märkl 2018-09-17 12:07:00 +02:00 committed by radare
parent 522ab3c84f
commit c05c85aa9f
11 changed files with 310 additions and 36 deletions

View File

@ -36,6 +36,7 @@ cache:
before_install:
- if [ "$TRAVIS_OS_NAME" != "osx" ]; then docker pull radareorg/r2-travis:latest || docker build -t radareorg/r2-travis:latest -f Dockerfile.travis . ; else rm -rf .nvm && git clone https://github.com/creationix/nvm.git .nvm && (cd .nvm && git checkout `git describe --abbrev=0 --tags`) && . .nvm/nvm.sh && nvm install 8.11.3; fi
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew install libuv ; fi
script:
- export PR_NAME=$(echo $TRAVIS_PULL_REQUEST_SLUG | cut -d'/' -f1)

View File

@ -71,6 +71,10 @@ LIBXXHASH=@LIBXXHASH@
SSL_CFLAGS=@SSL_CFLAGS@
SSL_LDFLAGS=@SSL_LDFLAGS@
HAVE_LIBUV=@HAVE_LIBUV@
LIBUV_CFLAGS=@LIBUV_CFLAGS@
LIBUV_LDFLAGS=@LIBUV_LDFLAGS@
GIT_TIP:=$(shell (git rev-parse HEAD 2>/dev/null || echo HEAD ))
GIT_TAP:=$(shell (git describe --tags 2>/dev/null || echo ${VERSION} ))

30
configure vendored
View File

@ -28,6 +28,7 @@ USE_ZIP=0
USE_XXHASH=0
WITH_GPL=1
WANT_OPENSSL=0
WANT_LIBUV=1
USE_RPATH=0
[ -z "${USERCC}" ] && USERCC="gcc"
[ -z "${USEROSTYPE}" ] && USEROSTYPE="auto"
@ -174,6 +175,7 @@ printf "\nOptional Features:
--with-sysxxhash force to use system's xxhash
--without-gpl do not build GPL code (grub, cxx, ... )
--with-openssl build with openssl if possible
--without-libuv disable libuv dependency
--with-rpath use rpath to build
--with-compiler Define compiler to use (see mk/) (USERCC=gcc)
--with-ostype Choose OS type ( gnulinux windows darwin haiku ) (USEROSTYPE=auto)
@ -229,9 +231,9 @@ echo "PKGNAME: radare2"
echo "VERSION: 3.0.0-git"
echo "LANGS: c"
echo "REQUIRED: libdl"
echo "OPTIONAL: libmagic libz libzip libxxhash libssl"
echo "PKG-CONFIG: capstone openssl"
echo "FLAGS: --disable-debugger --with-sysmagic --disable-loadlibs --without-fork --with-libr --with-syscapstone --with-syszip --with-sysxxhash --without-gpl --with-openssl --with-rpath --with-compiler=gcc --with-ostype=auto --with-libversion=xxx --without-jemalloc --with-checks-level=2"
echo "OPTIONAL: libmagic libz libzip libxxhash libssl liblibuv"
echo "PKG-CONFIG: capstone openssl libuv"
echo "FLAGS: --disable-debugger --with-sysmagic --disable-loadlibs --without-fork --with-libr --with-syscapstone --with-syszip --with-sysxxhash --without-gpl --with-openssl --without-libuv --with-rpath --with-compiler=gcc --with-ostype=auto --with-libversion=xxx --without-jemalloc --with-checks-level=2"
exit 0
;;
--cache-file)
@ -287,6 +289,7 @@ echo "FLAGS: --disable-debugger --with-sysmagic --disable-loadlibs --without
"--with-sysxxhash") USE_XXHASH="1"; ;;
"--without-gpl") WITH_GPL="0"; ;;
"--with-openssl") WANT_OPENSSL="1"; ;;
"--without-libuv") WANT_LIBUV="0"; ;;
"--with-rpath") USE_RPATH="1"; ;;
--with-compiler) if [ -z "${value}" ]; then USERCC="gcc"; else USERCC="${value}" ; fi ;;
--with-ostype) if [ -z "${value}" ]; then USEROSTYPE="auto"; else USEROSTYPE="${value}" ; fi ;;
@ -310,7 +313,7 @@ parse_options "$1"
shift
done
ENVWORDS="MANDIR INFODIR LIBDIR INCLUDEDIR LOCALSTATEDIR SYSCONFDIR DATADIR DOCDIR LIBEXECDIR SBINDIR BINDIR EPREFIX PREFIX SPREFIX TARGET HOST BUILD INSTALL INSTALL_LIB INSTALL_MAN INSTALL_PROGRAM INSTALL_PROGRAM_STRIP INSTALL_DIR INSTALL_SCRIPT INSTALL_DATA HOST_OS HOST_CPU BUILD_OS BUILD_CPU TARGET_OS TARGET_CPU PKGNAME VPATH VERSION CONTACT CONTACT_NAME CONTACT_MAIL CC CFLAGS CPPFLAGS LDFLAGS HAVE_LANG_C DEBUGGER HAVE_LIB_DL DL_LIBS HAVE_PATCH PATCH HAVE_GIT GIT HAVE_LIB_MAGIC USE_MAGIC USE_LIB_MAGIC LIBMAGIC LOADLIBS HAVE_FORK WITH_LIBR WITH_CAPSTONE CAPSTONE_CFLAGS CAPSTONE_LDFLAGS HAVE_PKGCFG_CAPSTONE USE_CAPSTONE HAVE_LIB_Z HAVE_LIB_ZIP USE_ZIP USE_LIB_ZIP LIBZIP HAVE_LIB_XXHASH USE_XXHASH USE_LIB_XXHASH LIBXXHASH WITH_GPL HAVE_DECL_ADDR_NO_RANDOMIZE HAVE_ARC4RANDOM_UNIFORM HAVE_EXPLICIT_BZERO HAVE_LIB_GMP HAVE_LIB_SSL SSL_CFLAGS SSL_LDFLAGS HAVE_PKGCFG_OPENSSL HAVE_OPENSSL WANT_OPENSSL USE_RPATH USERCC USEROSTYPE LIBVERSION HAVE_JEMALLOC R_CHECKS_LEVEL"
ENVWORDS="MANDIR INFODIR LIBDIR INCLUDEDIR LOCALSTATEDIR SYSCONFDIR DATADIR DOCDIR LIBEXECDIR SBINDIR BINDIR EPREFIX PREFIX SPREFIX TARGET HOST BUILD INSTALL INSTALL_LIB INSTALL_MAN INSTALL_PROGRAM INSTALL_PROGRAM_STRIP INSTALL_DIR INSTALL_SCRIPT INSTALL_DATA HOST_OS HOST_CPU BUILD_OS BUILD_CPU TARGET_OS TARGET_CPU PKGNAME VPATH VERSION CONTACT CONTACT_NAME CONTACT_MAIL CC CFLAGS CPPFLAGS LDFLAGS HAVE_LANG_C DEBUGGER HAVE_LIB_DL DL_LIBS HAVE_PATCH PATCH HAVE_GIT GIT HAVE_LIB_MAGIC USE_MAGIC USE_LIB_MAGIC LIBMAGIC LOADLIBS HAVE_FORK WITH_LIBR WITH_CAPSTONE CAPSTONE_CFLAGS CAPSTONE_LDFLAGS HAVE_PKGCFG_CAPSTONE USE_CAPSTONE HAVE_LIB_Z HAVE_LIB_ZIP USE_ZIP USE_LIB_ZIP LIBZIP HAVE_LIB_XXHASH USE_XXHASH USE_LIB_XXHASH LIBXXHASH WITH_GPL HAVE_DECL_ADDR_NO_RANDOMIZE HAVE_ARC4RANDOM_UNIFORM HAVE_EXPLICIT_BZERO HAVE_LIB_GMP HAVE_LIB_SSL SSL_CFLAGS SSL_LDFLAGS HAVE_PKGCFG_OPENSSL HAVE_OPENSSL WANT_OPENSSL HAVE_LIB_LIBUV LIBUV_CFLAGS LIBUV_LDFLAGS HAVE_PKGCFG_LIBUV HAVE_LIBUV WANT_LIBUV USE_RPATH USERCC USEROSTYPE LIBVERSION HAVE_JEMALLOC R_CHECKS_LEVEL"
create_environ
@ -516,6 +519,23 @@ if [ "$HAVE_LIB_SSL" = "0" ]; then
HAVE_OPENSSL="0"
else
SSL_LDFLAGS="-lssl"; fi; fi
check_library HAVE_LIB_LIBUV libuv 0
[ -z "${PKGCONFIG}" ] && PKGCONFIG=pkg-config
printf 'checking pkg-config flags for libuv... '
tmp=`${PKGCONFIG} --cflags libuv 2>/dev/null`
if [ $? != 0 ]; then echo no ; HAVE_PKGCFG_LIBUV=0;
else
LIBUV_CFLAGS=$tmp;
tmp=`${PKGCONFIG} --libs libuv 2>/dev/null`
if [ $? = 0 ]; then
echo yes; HAVE_PKGCFG_LIBUV=1;
LIBUV_LDFLAGS=$tmp; fi; fi
if [ ! "$LIBUV_LDFLAGS" = "" ]; then
HAVE_LIBUV="1"
else
HAVE_LIBUV="0"; fi
if [ "$WANT_LIBUV" = "0" ]; then
HAVE_LIBUV="0"; fi
if [ "$USEROSTYPE" = "auto" ]; then
if [ "$HOST_OS" = "mingw32_nt-6.2" ]; then
USEROSTYPE="mingw32"
@ -596,7 +616,7 @@ done
do_remove
echo
echo "Final report:"
for A in R_CHECKS_LEVEL PREFIX HAVE_LIB_GMP HAVE_OPENSSL USE_CAPSTONE HAVE_FORK VERSION USE_LIB_ZIP USE_LIB_MAGIC USE_LIB_XXHASH DEBUGGER CC USERCC HAVE_ARC4RANDOM_UNIFORM HAVE_EXPLICIT_BZERO USEROSTYPE LIBVERSION BUILD HOST TARGET ; do # REPORT
for A in R_CHECKS_LEVEL PREFIX HAVE_LIB_GMP HAVE_OPENSSL HAVE_LIBUV USE_CAPSTONE HAVE_FORK VERSION USE_LIB_ZIP USE_LIB_MAGIC USE_LIB_XXHASH DEBUGGER CC USERCC HAVE_ARC4RANDOM_UNIFORM HAVE_EXPLICIT_BZERO USEROSTYPE LIBVERSION BUILD HOST TARGET ; do # REPORT
eval VAL="\$${A}"
[ -z "${VAL}" ] && VAL="(null)"
echo " - ${A} = ${VAL}"

View File

@ -96,6 +96,18 @@ IFNULL SSL_LDFLAGS {
}
}
CHKLIB libuv
PKGCFG LIBUV_CFLAGS LIBUV_LDFLAGS libuv
IFNOTNULL LIBUV_LDFLAGS {
HAVE_LIBUV = 1 ;
}{
HAVE_LIBUV = 0 ;
}
ARG_WITHOUT WANT_LIBUV libuv disable libuv dependency ;
IFNOT WANT_LIBUV {
HAVE_LIBUV = 0 ;
}
ARG_WITH USE_RPATH rpath use rpath to build ;
(( rules for the compiler ))
@ -150,7 +162,7 @@ IFEQ LIBVERSION xxx ; {
ARG_WITH R_CHECKS_LEVEL=2 checks-level value between 0 and 3 to enable different level of assert (see R_CHECKS_LEVEL) ;
REPORT R_CHECKS_LEVEL PREFIX HAVE_LIB_GMP HAVE_OPENSSL USE_CAPSTONE HAVE_FORK
REPORT R_CHECKS_LEVEL PREFIX HAVE_LIB_GMP HAVE_OPENSSL HAVE_LIBUV USE_CAPSTONE HAVE_FORK
VERSION USE_LIB_ZIP USE_LIB_MAGIC USE_LIB_XXHASH DEBUGGER CC USERCC HAVE_ARC4RANDOM_UNIFORM
HAVE_EXPLICIT_BZERO USEROSTYPE LIBVERSION BUILD HOST TARGET ;

View File

@ -222,6 +222,7 @@ R_API int r_cons_fgets(char *buf, int len, int argc, const char **argv) {
r_cons_enable_mouse (false);
r_cons_flush ();
#endif
errno = 0;
if (cons->user_fgets) {
RETURN (cons->user_fgets (buf, len));
}

View File

@ -5,8 +5,6 @@ NAME=r_core
DEPS=r_config r_cons r_io r_util r_flag r_asm
DEPS+=r_debug r_hash r_bin r_lang r_io r_anal r_parse r_bp r_egg
DEPS+=r_reg r_search r_syscall r_socket r_fs r_magic r_crypto
PCCFLAGS=@SSL_CFLAGS@ @CAPSTONE_CFLAGS@
PCLIBS=@SSL_LDFLAGS@ @CAPSTONE_LDFLAGS@
OBJS=core.o cmd.o cfile.o cconfig.o visual.o cio.o yank.o libs.o graph.o
OBJS+=fortune.o hack.o vasm.o patch.o cbin.o log.o rtr.o cmd_api.o
@ -26,6 +24,11 @@ ifeq ($(USE_LIB_MAGIC),1)
LDFLAGS+=${LIBMAGIC}
endif
ifeq ($(HAVE_LIBUV),1)
CFLAGS+=${LIBUV_CFLAGS}
LDFLAGS+=${LIBUV_LDFLAGS}
endif
first:: all
include ${STATIC_CORE_PLUGINS}

View File

@ -67,10 +67,8 @@ if host_machine.system() != 'windows'
endif
r_core_inc = [platform_inc, include_directories(r_core_inc)]
r_core = library('r_core', files,
include_directories: r_core_inc,
c_args: library_cflags,
dependencies: [
r_core_deps = [
r_util_dep,
r_reg_dep,
r_syscall_dep,
@ -97,7 +95,16 @@ r_core = library('r_core', files,
spp_dep,
gdb_dep,
java_dep
],
]
if use_libuv
r_core_deps += libuv_dep
endif
r_core = library('r_core', files,
include_directories: r_core_inc,
c_args: library_cflags,
dependencies: r_core_deps,
install: true,
implicit_include_directories: false,
soversion: r2_libversion

View File

@ -5,6 +5,10 @@
#include "gdb/include/libgdbr.h"
#include "gdb/include/gdbserver/core.h"
#if HAVE_LIBUV
#include <uv.h>
#endif
#if 0
SECURITY IMPLICATIONS
=====================
@ -1883,6 +1887,206 @@ R_API char *r_core_rtr_cmds_query (RCore *core, const char *host, const char *po
return rbuf;
}
#if HAVE_LIBUV
typedef struct rtr_cmds_context_t {
uv_tcp_t server;
RPVector clients;
void *bed;
} rtr_cmds_context;
typedef struct rtr_cmds_client_context_t {
RCore *core;
char buf[4096];
char *res;
size_t len;
uv_tcp_t *client;
} rtr_cmds_client_context;
static void rtr_cmds_client_close(uv_tcp_t *client, bool remove) {
uv_loop_t *loop = client->loop;
rtr_cmds_context *context = loop->data;
if (remove) {
size_t i;
for (i = 0; i < r_pvector_len (&context->clients); i++) {
if (r_pvector_at (&context->clients, i) == client) {
r_pvector_remove_at (&context->clients, i);
break;
}
}
}
rtr_cmds_client_context *client_context = client->data;
uv_close ((uv_handle_t *) client, (uv_close_cb) free);
free (client_context->res);
free (client_context);
}
static void rtr_cmds_alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {
rtr_cmds_client_context *context = handle->data;
buf->base = context->buf + context->len;
buf->len = sizeof (context->buf) - context->len - 1;
}
static void rtr_cmds_write(uv_write_t *req, int status) {
rtr_cmds_client_context *context = req->data;
if (status) {
eprintf ("Write error: %s\n", uv_strerror (status));
}
free (req);
rtr_cmds_client_close (context->client, true);
}
static void rtr_cmds_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) {
rtr_cmds_context *context = client->loop->data;
rtr_cmds_client_context *client_context = client->data;
if (nread < 0) {
if (nread != UV_EOF) {
eprintf ("Failed to read: %s\n", uv_err_name ((int) nread));
}
rtr_cmds_client_close ((uv_tcp_t *) client, true);
return;
} else if (nread == 0) {
return;
}
buf->base[nread] = '\0';
char *end = strchr (buf->base, '\n');
if (!end) {
return;
}
*end = '\0';
r_cons_sleep_end (context->bed);
client_context->res = r_core_cmd_str (client_context->core, (const char *)client_context->buf);
context->bed = r_cons_sleep_begin ();
if (!client_context->res || !*client_context->res) {
free (client_context->res);
client_context->res = strdup ("\n");
}
if (!client_context->res || (!r_config_get_i (client_context->core->config, "scr.prompt") &&
!strcmp ((char *)buf, "q!")) ||
!strcmp ((char *)buf, ".--")) {
rtr_cmds_client_close ((uv_tcp_t *) client, true);
return;
}
uv_write_t *req = R_NEW (uv_write_t);
req->data = client_context;
uv_buf_t wrbuf = uv_buf_init (client_context->res, (unsigned int) strlen (client_context->res));
uv_write (req, client, &wrbuf, 1, rtr_cmds_write);
uv_read_stop (client);
}
static void rtr_cmds_new_connection(uv_stream_t *server, int status) {
if (status < 0) {
eprintf ("New connection error: %s\n", uv_strerror (status));
return;
}
rtr_cmds_context *context = server->loop->data;
uv_tcp_t *client = R_NEW (uv_tcp_t);
if (!client) {
return;
}
uv_tcp_init (server->loop, client);
if (uv_accept (server, (uv_stream_t *)client) == 0) {
rtr_cmds_client_context *client_context = R_NEW (rtr_cmds_client_context);
if (!client_context) {
uv_close ((uv_handle_t *)client, NULL);
return;
}
client_context->core = server->data;
client_context->len = 0;
client_context->buf[0] = '\0';
client_context->res = NULL;
client_context->client = client;
client->data = client_context;
uv_read_start ((uv_stream_t *)client, rtr_cmds_alloc_buffer, rtr_cmds_read);
r_pvector_push (&context->clients, client);
} else {
uv_close ((uv_handle_t *)client, NULL);
}
}
static void rtr_cmds_stop(uv_async_t *handle) {
uv_close ((uv_handle_t *) handle, NULL);
rtr_cmds_context *context = handle->loop->data;
uv_close ((uv_handle_t *) &context->server, NULL);
void **it;
r_pvector_foreach (&context->clients, it) {
uv_tcp_t *client = *it;
rtr_cmds_client_close (client, false);
}
}
static void rtr_cmds_break(uv_async_t *async) {
uv_async_send (async);
}
R_API int r_core_rtr_cmds(RCore *core, const char *port) {
if (!port || port[0] == '?') {
r_cons_printf ("Usage: .:[tcp-port] run r2 commands for clients\n");
return 0;
}
uv_loop_t *loop = R_NEW (uv_loop_t);
if (!loop) {
return 0;
}
uv_loop_init (loop);
rtr_cmds_context context;
r_pvector_init (&context.clients, NULL);
loop->data = &context;
context.server.data = core;
uv_tcp_init (loop, &context.server);
struct sockaddr_in addr;
bool local = (bool) r_config_get_i(core->config, "tcp.islocal");
int porti = r_socket_port_by_name (port);
uv_ip4_addr (local ? "127.0.0.1" : "0.0.0.0", porti, &addr);
uv_tcp_bind (&context.server, (const struct sockaddr *) &addr, 0);
int r = uv_listen ((uv_stream_t *)&context.server, 32, rtr_cmds_new_connection);
if (r) {
eprintf ("Failed to listen: %s\n", uv_strerror (r));
goto beach;
}
uv_async_t stop_async;
uv_async_init (loop, &stop_async, rtr_cmds_stop);
r_cons_break_push ((RConsBreak) rtr_cmds_break, &stop_async);
context.bed = r_cons_sleep_begin ();
uv_run (loop, UV_RUN_DEFAULT);
r_cons_sleep_end (context.bed);
r_cons_break_pop ();
beach:
uv_loop_close (loop);
free (loop);
r_pvector_clear (&context.clients);
return 0;
}
#else
R_API int r_core_rtr_cmds (RCore *core, const char *port) {
unsigned char buf[4097];
RSocket *ch = NULL;
@ -1948,3 +2152,5 @@ R_API int r_core_rtr_cmds (RCore *core, const char *port) {
r_socket_free (ch);
return 0;
}
#endif

View File

@ -86,6 +86,7 @@
#define USE_LIB_XXHASH @USE_LIB_XXHASH@
#ifndef HAVE_LIB_SSL
#define HAVE_LIB_SSL @HAVE_OPENSSL@
#define HAVE_LIBUV @HAVE_LIBUV@
#endif
#define HAVE_FORK @HAVE_FORK@

View File

@ -237,6 +237,23 @@ else
message('Using bundled openssl code')
endif
# handle libuv library
if get_option('use_libuv')
libuv_dep = dependency('libuv', required: false)
use_libuv = libuv_dep.found()
if not libuv_dep.found()
warning('use_libuv option was set to true, but libuv was not found.')
endif
else
use_libuv = false
endif
if use_libuv
message('Using libuv')
else
message('Not using libuv, thus using fallback server implementations')
endif
userconf = configuration_data()
userconf.set('R_CHECKS_LEVEL', get_option('checks_level'))
userconf.set('HAVE_LIB_MAGIC', sys_magic.found().to_int())
@ -259,6 +276,7 @@ userconf.set('PLUGINS', r2_plugins)
userconf.set('EXTRAS', r2_extras)
userconf.set('BINDINGS', r2_bindings)
userconf.set('HAVE_OPENSSL', use_sys_openssl.to_int())
userconf.set('HAVE_LIBUV', use_libuv.to_int())
userconf.set('HAVE_FORK', 1)
userconf.set('WITH_GPL', 1)
if host_machine.system() == 'windows'

View File

@ -21,3 +21,4 @@ option('use_sys_zlib', type: 'boolean', value: false)
option('use_sys_lz4', type: 'boolean', value: false)
option('use_sys_xxhash', type: 'boolean', value: false)
option('use_sys_openssl', type: 'boolean', value: false)
option('use_libuv', type: 'boolean', value: true)