From 6ca09c230d4b01ecf4cf7b54e6048191c2fb7d9a Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 1 Oct 2014 18:48:42 +0200 Subject: Integrate asynchronous DNS resolver (c-ares) with libosmocore As osmocom-style applications are centered around a single select loop, DNS queries need to be handled asynchronously to prevent blocking the entire program. The c-ares library is a popular option for async DNS resolving. However, it requires integration with the select loop of the application, which in our case lives inside libosmocore select.c. This patch adds the required integration. The backside is that it adds a mandatory dependency to c-ares (libcares), as well as 2-3 additional branches to every call to osmo_select_main(). --- configure.ac | 2 ++ include/Makefile.am | 1 + include/osmocom/core/ares.h | 10 ++++++++++ libosmocore.pc.in | 2 +- src/Makefile.am | 6 +++--- src/select.c | 34 +++++++++++++++++++++++++++++++--- tests/Makefile.am | 7 +++++-- tests/ares/ares_test.ok | 2 ++ tests/testsuite.at | 6 ++++++ 9 files changed, 61 insertions(+), 9 deletions(-) create mode 100644 include/osmocom/core/ares.h create mode 100644 tests/ares/ares_test.ok diff --git a/configure.ac b/configure.ac index deaa8bf7..046016eb 100644 --- a/configure.ac +++ b/configure.ac @@ -17,6 +17,8 @@ LT_INIT([pic-only]) AC_CONFIG_MACRO_DIR([m4]) +PKG_CHECK_MODULES(LIBCARES, libcares) + dnl check os: some linker flags not available on osx case $host in *-darwin*) diff --git a/include/Makefile.am b/include/Makefile.am index 9f5c9662..7d054c94 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,6 +1,7 @@ nobase_include_HEADERS = \ osmocom/codec/codec.h \ osmocom/core/application.h \ + osmocom/core/ares.h \ osmocom/core/backtrace.h \ osmocom/core/bit16gen.h \ osmocom/core/bit32gen.h \ diff --git a/include/osmocom/core/ares.h b/include/osmocom/core/ares.h new file mode 100644 index 00000000..8abd3db1 --- /dev/null +++ b/include/osmocom/core/ares.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +#include + +extern struct value_string ares_status_strs[25]; +extern ares_channel osmo_ares_channel; + +int osmo_ares_init(); diff --git a/libosmocore.pc.in b/libosmocore.pc.in index 7c298693..34cb294c 100644 --- a/libosmocore.pc.in +++ b/libosmocore.pc.in @@ -6,6 +6,6 @@ includedir=@includedir@ Name: Osmocom Core Library Description: C Utility Library Version: @VERSION@ -Libs: -L${libdir} -losmocore +Libs: -L${libdir} -losmocore -lcares Cflags: -I${includedir}/ diff --git a/src/Makefile.am b/src/Makefile.am index f2b1b838..d36a36f5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,11 +2,11 @@ # Please read Chapter 6 "Library interface versions" of the libtool documentation before making any modification LIBVERSION=5:0:0 -AM_CFLAGS = -Wall $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)/include +AM_CFLAGS = -Wall $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)/include -I$(LIBCARES_CFLAGS) lib_LTLIBRARIES = libosmocore.la -libosmocore_la_LIBADD = $(BACKTRACE_LIB) +libosmocore_la_LIBADD = $(BACKTRACE_LIB) $(LIBCARES_LIBS) libosmocore_la_SOURCES = timer.c select.c signal.c msgb.c bits.c \ bitvec.c statistics.c \ write_queue.c utils.c socket.c \ @@ -14,7 +14,7 @@ libosmocore_la_SOURCES = timer.c select.c signal.c msgb.c bits.c \ gsmtap_util.c crc16.c panic.c backtrace.c \ conv.c application.c rbtree.c strrb.c \ loggingrb.c crc8gen.c crc16gen.c crc32gen.c crc64gen.c \ - macaddr.c + macaddr.c ares.c BUILT_SOURCES = crc8gen.c crc16gen.c crc32gen.c crc64gen.c diff --git a/src/select.c b/src/select.c index b29e5c5e..8a967223 100644 --- a/src/select.c +++ b/src/select.c @@ -22,9 +22,12 @@ #include #include +#include + #include #include #include +#include #include "../config.h" @@ -103,7 +106,7 @@ int osmo_select_main(int polling) struct osmo_fd *ufd, *tmp; fd_set readset, writeset, exceptset; int work = 0, rc; - struct timeval no_time = {0, 0}; + struct timeval *final_tv, no_time = {0, 0}; FD_ZERO(&readset); FD_ZERO(&writeset); @@ -121,14 +124,39 @@ int osmo_select_main(int polling) FD_SET(ufd->fd, &exceptset); } + if (osmo_ares_channel) { + /* patch in the socket file descripturs used by c-ares library */ + rc = ares_fds(osmo_ares_channel, &readset, &writeset); + if (rc > maxfd) + maxfd = rc; + } + osmo_timers_check(); - if (!polling) + if (!polling) { + struct timeval *timer_tv; + struct timeval tv; + osmo_timers_prepare(); - rc = select(maxfd+1, &readset, &writeset, &exceptset, polling ? &no_time : osmo_timers_nearest()); + /* obtain nearest timer timeout */ + timer_tv = osmo_timers_nearest(); + /* determine if ares has a nearer timeout */ + if (osmo_ares_channel) + final_tv = ares_timeout(osmo_ares_channel, timer_tv, &tv); + else + final_tv = timer_tv; + } else + final_tv = &no_time; + + rc = select(maxfd+1, &readset, &writeset, &exceptset, final_tv); if (rc < 0) return 0; + /* process any c-ares filedescriptors (if any) and take care of + * timeouts */ + if (osmo_ares_channel) + ares_process(osmo_ares_channel, &readset, &writeset); + /* fire timers */ osmo_timers_update(); diff --git a/tests/Makefile.am b/tests/Makefile.am index ea4bf9ca..40b6d0b1 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -7,7 +7,8 @@ check_PROGRAMS = timer/timer_test sms/sms_test ussd/ussd_test \ gb/bssgp_fc_test gb/gprs_ns_test kasumi/kasumi_test \ logging/logging_test fr/fr_test \ loggingrb/loggingrb_test strrb/strrb_test \ - vty/vty_test comp128/comp128_test utils/utils_test + vty/vty_test comp128/comp128_test utils/utils_test \ + ares/ares_test if ENABLE_MSGFILE check_PROGRAMS += msgfile/msgfile_test @@ -80,6 +81,8 @@ strrb_strrb_test_LDADD = $(top_builddir)/src/libosmocore.la vty_vty_test_SOURCES = vty/vty_test.c vty_vty_test_LDADD = $(top_builddir)/src/vty/libosmovty.la $(top_builddir)/src/libosmocore.la +ares_ares_test_SOURCES = ares/ares_test.c +ares_ares_test_LDADD = $(top_builddir)/src/libosmocore.la $(LIBCARES_LIBS) # The `:;' works around a Bash 3.2 bug when the output is not writeable. $(srcdir)/package.m4: $(top_srcdir)/configure.ac @@ -112,7 +115,7 @@ EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE) \ fr/fr_test.ok loggingrb/logging_test.ok \ loggingrb/logging_test.err strrb/strrb_test.ok \ vty/vty_test.ok comp128/comp128_test.ok \ - utils/utils_test.ok + utils/utils_test.ok ares/ares_test.ok DISTCLEANFILES = atconfig diff --git a/tests/ares/ares_test.ok b/tests/ares/ares_test.ok new file mode 100644 index 00000000..507a6a51 --- /dev/null +++ b/tests/ares/ares_test.ok @@ -0,0 +1,2 @@ +Callback called: status=0, timeouts=0 +localhost.localdomain -> 127.0.0.1 diff --git a/tests/testsuite.at b/tests/testsuite.at index 7ce2ee80..2886ae24 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -142,3 +142,9 @@ AT_KEYWORDS([timer]) cat $abs_srcdir/timer/timer_test.ok > expout AT_CHECK([$abs_top_builddir/tests/timer/timer_test -s 5], [0], [expout], [ignore]) AT_CLEANUP + +AT_SETUP([ares]) +AT_KEYWORDS([ares]) +cat $abs_srcdir/ares/ares_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/ares/ares_test], [0], [expout], [ignore]) +AT_CLEANUP -- cgit v1.2.3