diff --git a/src/Makefile.am b/src/Makefile.am index 2757b53a..6c3d5e3f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -141,6 +141,7 @@ noinst_HEADERS = \ textfile_sub_source.hh \ textview_curses.hh \ time_T.hh \ + timer.hh \ top_status_source.hh \ view_curses.hh \ vt52_curses.hh \ @@ -203,6 +204,7 @@ libdiag_a_SOURCES = \ sqlite-extension-func.c \ statusview_curses.cc \ string-extension-functions.cc \ + timer.cc \ pcrepp.cc \ piper_proc.cc \ sql_util.cc \ diff --git a/src/pretty_printer.hh b/src/pretty_printer.hh index aa90cb18..e71d4ba1 100644 --- a/src/pretty_printer.hh +++ b/src/pretty_printer.hh @@ -30,18 +30,32 @@ #ifndef __pretty_printer_hh #define __pretty_printer_hh +#include #include #include #include #include +#include #include #include #include +#include "timer.hh" #include "ansi_scrubber.hh" #include "data_scanner.hh" +static sig_atomic_t reverse_lookup_enabled = 1; + +void sigalrm_handler(int sig) +{ + if (sig == SIGALRM) + { + reverse_lookup_enabled = 0; + } +} + + class pretty_printer { public: @@ -149,14 +163,26 @@ private: require(0); break; } - if (rc == 1) { - while ((rc = getnameinfo((struct sockaddr *)&sa, socklen, - buffer, sizeof(buffer), NULL, 0, - NI_NAMEREQD)) == EAI_AGAIN) { - usleep(1000); + if (rc == 1 && reverse_lookup_enabled) { + const struct timeval timeout = {3, 0}; + + { + timer::interrupt_timer t(timeout, sigalrm_handler); + if (t.arm_timer() == 0) { + rc = getnameinfo((struct sockaddr *)&sa, socklen, + buffer, sizeof(buffer), NULL, 0, + NI_NAMEREQD); + if (rc == 0) { + result = buffer; + } + } + else { + log_error("Unable to set timer, disabling reverse lookup"); + reverse_lookup_enabled = 0; + } } - if (rc == 0) { - result = buffer; + if (!reverse_lookup_enabled) { + log_info("Reverse lookup in pretty-print view disabled"); } } this->pp_stream << " " << ANSI_UNDERLINE_START << diff --git a/src/timer.cc b/src/timer.cc new file mode 100644 index 00000000..5dc3eb68 --- /dev/null +++ b/src/timer.cc @@ -0,0 +1,112 @@ +/** + * Copyright (c) 2015, Suresh Sundriyal + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "timer.hh" +#include "lnav_log.hh" + +const struct itimerval disable = { + { 0, 0 }, + { 0, 0 } +}; + +timer::error::error(int err):e_err(err) { } + +timer::interrupt_timer::interrupt_timer(struct timeval t, + sighandler_t_ sighandler=SIG_IGN) : new_handler(sighandler), + old_handler(NULL), new_val((struct itimerval){{0,0},t}), + old_val(disable), armed(false) { } + +int timer::interrupt_timer::arm_timer() { + // Disable the interval timer before setting the handler and arming the + // interval timer or else we will have a race-condition where the timer + // might fire and the appropriate handler might not be set. + if (setitimer(ITIMER_REAL, &disable, &this->old_val) != 0) { + log_error("Unable to disable the timer: %s", + strerror(errno)); + return -1; + } + this->old_handler = signal(SIGALRM, this->new_handler); + if (this->old_handler == SIG_ERR) { + log_error("Unable to set the signal handler: %s", + strerror(errno)); + if (setitimer(ITIMER_REAL, &this->old_val, NULL) != 0) { + log_error("Unable to reset the interrupt timer: %s", + strerror(errno)); + throw timer::error(errno); + } + return -1; + } + + if (setitimer(ITIMER_REAL, &this->new_val, NULL) != 0) { + if(signal(SIGALRM, this->old_handler) == SIG_ERR) { + log_error("Unable to reset the signal handler: %s", + strerror(errno)); + throw timer::error(errno); + } + log_error("Unable to set the timer: %s", strerror(errno)); + return -1; + } + this->armed = true; + return 0; +} + +bool timer::interrupt_timer::is_armed() { + return this->armed; +} + +void timer::interrupt_timer::disarm_timer() { + if (this->armed) { + // Disable the interval timer before resetting the handler and rearming + // the previous interval timer or else we will have a race-condition + // where the timer might fire and the appropriate handler might not be + // set. + if (setitimer(ITIMER_REAL, &disable, NULL) != 0) { + log_error("Failed to disable the timer: %s", + strerror(errno)); + throw timer::error(errno); + } + if (signal(SIGALRM, this->old_handler) == SIG_ERR) { + log_error("Failed to reinstall previous SIGALRM handler: %s", + strerror(errno)); + throw timer::error(errno); + } + if (setitimer(ITIMER_REAL, &this->old_val, NULL) != 0) { + log_error("Failed to reset the timer to previous value: %s", + strerror(errno)); + throw timer::error(errno); + } + this->armed = false; + this->old_val = disable; + this->old_handler = NULL; + } +} + +timer::interrupt_timer::~interrupt_timer() { + this->disarm_timer(); +} diff --git a/src/timer.hh b/src/timer.hh new file mode 100644 index 00000000..5d4e1cd2 --- /dev/null +++ b/src/timer.hh @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2015, Suresh Sundriyal + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef timer_hh +#define timer_hh + +#include +#include +#include +#include +#include + +// Linux and BSD seem to name the function pointer to signal handler differently. +// Linux names it 'sighandler_t' and BSD names it 'sig_t'. Instead of depending +// on configure scripts to find out the type name, typedef it right here. +typedef void (*sighandler_t_)(int); + +namespace timer{ +class error : public std::exception { + public: + error(int err); + int e_err; +}; + +class interrupt_timer { + public: + interrupt_timer(struct timeval, sighandler_t_); + int arm_timer(); + void disarm_timer(); + bool is_armed(); + ~interrupt_timer(); + private: + sighandler_t_ new_handler, old_handler; + struct itimerval new_val, old_val; + bool armed; +}; +} +#endif