Merge pull request #228 from sureshsundriyal/wip4

[pretty] Don't wait indefinitely for reverse IP lookups.
This commit is contained in:
Tim Stack 2015-04-24 12:59:51 -07:00
commit 43104ed687
4 changed files with 211 additions and 7 deletions

View File

@ -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 \

View File

@ -30,18 +30,32 @@
#ifndef __pretty_printer_hh
#define __pretty_printer_hh
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <signal.h>
#include <stack>
#include <deque>
#include <sstream>
#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 <<

112
src/timer.cc Normal file
View File

@ -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();
}

64
src/timer.hh Normal file
View File

@ -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 <errno.h>
#include <signal.h>
#include <exception>
#include <sys/time.h>
#include <sys/types.h>
// 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