You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
315 lines
7.7 KiB
315 lines
7.7 KiB
/*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
* Author : Richard GAYRAUD - 04 Nov 2003
|
|
* From Hewlett Packard Company.
|
|
*/
|
|
|
|
/****
|
|
* Screen.cpp : Simple curses & logfile encapsulation
|
|
*/
|
|
|
|
#include "stat.hpp"
|
|
#include "sipp.hpp"
|
|
|
|
#include <curses.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
#include <screen.hpp>
|
|
#include <errno.h>
|
|
#include <sys/time.h>
|
|
#include <sys/resource.h>
|
|
|
|
#ifdef __SUNOS
|
|
#include<stdarg.h>
|
|
#endif
|
|
|
|
#include <unistd.h>
|
|
|
|
extern bool timeout_exit;
|
|
|
|
unsigned long screen_errors;
|
|
int screen_inited = 0;
|
|
char screen_exename[255];
|
|
extern void releaseGlobalAllocations();
|
|
extern void stop_all_traces();
|
|
extern bool backgroundMode;
|
|
|
|
void (*screen_exit_handler)();
|
|
|
|
/* Clock must be a pointer to struct timeval */
|
|
#define GET_TIME(clock) \
|
|
{ \
|
|
struct timezone tzp; \
|
|
gettimeofday (clock, &tzp); \
|
|
}
|
|
|
|
/* ERR is actually -1, but this prevents us from needing to use curses.h in
|
|
* sipp.cpp. */
|
|
int screen_readkey()
|
|
{
|
|
int c = getch();
|
|
if (c == ERR) {
|
|
return -1;
|
|
}
|
|
return c;
|
|
}
|
|
|
|
void screen_exit(int rc)
|
|
{
|
|
unsigned long counter_value_failed=0;
|
|
unsigned long counter_value_success=0;
|
|
|
|
/* Some signals may be delivered twice during exit() execution,
|
|
* and we must prevent all this from beeing done twice */
|
|
|
|
{
|
|
static int already_exited = 0;
|
|
if(already_exited) {
|
|
return;
|
|
}
|
|
already_exited = 1;
|
|
}
|
|
|
|
if( backgroundMode == false )
|
|
endwin();
|
|
|
|
if(screen_exit_handler) {
|
|
screen_exit_handler();
|
|
}
|
|
|
|
if(screen_errors) {
|
|
fprintf(stderr, "%s", screen_last_error);
|
|
if(screen_errors > 1) {
|
|
if (screen_logfile[0] != (char)0) {
|
|
fprintf(stderr,
|
|
"%s: There were more errors, see '%s' file\n",
|
|
screen_exename, screen_logfile);
|
|
} else {
|
|
fprintf(stderr,
|
|
"%s: There were more errors, enable -trace_err to log them.\n",
|
|
screen_exename);
|
|
}
|
|
}
|
|
fflush(stderr);
|
|
}
|
|
|
|
// Get failed calls counter value before releasing objects
|
|
if (display_scenario) {
|
|
counter_value_failed = display_scenario->stats->GetStat (CStat::CPT_C_FailedCall);
|
|
counter_value_success = display_scenario->stats->GetStat (CStat::CPT_C_SuccessfulCall);
|
|
} else {
|
|
rc = EXIT_TEST_FAILED;
|
|
}
|
|
|
|
releaseGlobalAllocations();
|
|
|
|
if (rc != EXIT_TEST_RES_UNKNOWN) {
|
|
// Exit is not a normal exit. Just use the passed exit code.
|
|
exit(rc);
|
|
} else {
|
|
// Normal exit: we need to determine if the calls were all
|
|
// successful or not.
|
|
// In order to compute the return code, get the counter
|
|
// of failed calls. If there is 0 failed calls, then everything is OK!
|
|
if (counter_value_failed == 0) {
|
|
|
|
if ((timeout_exit) && (counter_value_success < 1)) {
|
|
|
|
exit (EXIT_TEST_RES_INTERNAL);
|
|
} else {
|
|
exit(EXIT_TEST_OK);
|
|
}
|
|
} else {
|
|
exit(EXIT_TEST_FAILED);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Exit handler for Curses */
|
|
|
|
void screen_quit()
|
|
{
|
|
screen_exit(EXIT_TEST_RES_UNKNOWN);
|
|
}
|
|
|
|
|
|
void manage_oversized_file()
|
|
{
|
|
FILE * f;
|
|
char L_file_name [MAX_PATH];
|
|
struct timeval currentTime;
|
|
static int managing = 0;
|
|
|
|
if(managing) return; //we can receive this signal more than once
|
|
|
|
managing = 1;
|
|
|
|
sprintf (L_file_name, "%s_%d_traces_oversized.log", scenario_file, getpid());
|
|
f = fopen(L_file_name, "w");
|
|
if(!f) ERROR_NO("Unable to open special error file\n");
|
|
GET_TIME (¤tTime);
|
|
fprintf(f,
|
|
"-------------------------------------------- %s\n"
|
|
"Max file size reached - no more logs\n",
|
|
CStat::formatTime(¤tTime));
|
|
fflush(f);
|
|
stop_all_traces();
|
|
print_all_responses = 0;
|
|
error_lfi.fptr = NULL;
|
|
}
|
|
|
|
|
|
void screen_clear()
|
|
{
|
|
printf("\033[2J");
|
|
}
|
|
|
|
void screen_set_exename(char * exe_name)
|
|
{
|
|
strcpy(screen_exename, exe_name);
|
|
}
|
|
|
|
void screen_init(void (*exit_handler)())
|
|
{
|
|
struct sigaction action_quit, action_file_size_exceeded;
|
|
|
|
screen_inited = 1;
|
|
screen_exit_handler = exit_handler;
|
|
|
|
if (backgroundMode == false) {
|
|
/* Initializes curses and signals */
|
|
initscr();
|
|
/* Enhance performances and display */
|
|
noecho();
|
|
}
|
|
|
|
/* Map exit handlers to curses reset procedure */
|
|
memset(&action_quit, 0, sizeof(action_quit));
|
|
memset(&action_file_size_exceeded, 0, sizeof(action_file_size_exceeded));
|
|
(*(void **)(&(action_quit.sa_handler)))=(void *)screen_quit;
|
|
(*(void **)(&(action_file_size_exceeded.sa_handler)))=(void *)manage_oversized_file;
|
|
sigaction(SIGTERM, &action_quit, NULL);
|
|
sigaction(SIGINT, &action_quit, NULL);
|
|
sigaction(SIGKILL, &action_quit, NULL);
|
|
sigaction(SIGXFSZ, &action_file_size_exceeded, NULL); // avoid core dump if the max file size is exceeded
|
|
|
|
if (backgroundMode == false) {
|
|
screen_clear();
|
|
}
|
|
}
|
|
|
|
static void _screen_error(int fatal, bool use_errno, int error, const char *fmt, va_list ap)
|
|
{
|
|
static unsigned long long count = 0;
|
|
char * c = screen_last_error;
|
|
struct timeval currentTime;
|
|
|
|
CStat::globalStat(fatal ? CStat::E_FATAL_ERRORS : CStat::E_WARNING);
|
|
|
|
GET_TIME (¤tTime);
|
|
|
|
c+= sprintf(c, "%s: ", CStat::formatTime(¤tTime));
|
|
c+= vsprintf(c, fmt, ap);
|
|
if (use_errno) {
|
|
c += sprintf(c, ", errno = %d (%s)", error, strerror(error));
|
|
}
|
|
c+= sprintf(c, ".\n");
|
|
screen_errors++;
|
|
|
|
if(screen_inited && !error_lfi.fptr && print_all_responses) {
|
|
rotate_errorf();
|
|
if(!error_lfi.fptr) {
|
|
c += sprintf(c, "%s: Unable to create '%s': %s.\n",
|
|
screen_exename, screen_logfile, strerror(errno));
|
|
screen_exit(EXIT_FATAL_ERROR);
|
|
} else {
|
|
fprintf(error_lfi.fptr, "%s: The following events occured:\n",
|
|
screen_exename);
|
|
fflush(error_lfi.fptr);
|
|
}
|
|
}
|
|
|
|
if(error_lfi.fptr) {
|
|
count += fprintf(error_lfi.fptr, "%s", screen_last_error);
|
|
fflush(error_lfi.fptr);
|
|
if (ringbuffer_size && count > ringbuffer_size) {
|
|
rotate_errorf();
|
|
count = 0;
|
|
}
|
|
if (max_log_size && count > max_log_size) {
|
|
print_all_responses = 0;
|
|
if (error_lfi.fptr) {
|
|
fflush(error_lfi.fptr);
|
|
fclose(error_lfi.fptr);
|
|
error_lfi.fptr = NULL;
|
|
error_lfi.overwrite = false;
|
|
}
|
|
}
|
|
} else if (fatal) {
|
|
fprintf(stderr, "%s", screen_last_error);
|
|
fflush(stderr);
|
|
}
|
|
|
|
if(fatal) {
|
|
if(!screen_inited) {
|
|
if(error == EADDRINUSE) {
|
|
exit(EXIT_BIND_ERROR);
|
|
} else {
|
|
exit(EXIT_FATAL_ERROR);
|
|
}
|
|
} else {
|
|
if(error == EADDRINUSE) {
|
|
screen_exit(EXIT_BIND_ERROR);
|
|
} else {
|
|
screen_exit(EXIT_FATAL_ERROR);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
extern "C" {
|
|
void ERROR(const char *fmt, ...) {
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
_screen_error(true, false, 0, fmt, ap);
|
|
va_end(ap);
|
|
assert(0);
|
|
}
|
|
|
|
void ERROR_NO(const char *fmt, ...) {
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
_screen_error(true, true, errno, fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
void WARNING(const char *fmt, ...) {
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
_screen_error(false, false, 0, fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
void WARNING_NO(const char *fmt, ...) {
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
_screen_error(false, true, errno, fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
}
|