/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- main
- process
- find_stats
- get_sent_recv
- parse_comline
- c_initialize
- c_initialize
- c_ipc_socloc_init
- app_out
- term_app
/* ialive - Program to test whether the Internet is up and active.
Rick Smereka, Copyright (C) 2006.
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, get a copy via the Internet at
http://gnu.org/copyleft/gpl.html or write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston,
MA 02111-1307 USA
You can contact the author via email at rsmereka@future-lab.com
Program syntax:
ialive [-c nn] [-b] [-q] [-p ping_dest] [-l [log_file]]
Where:
'c' is the number of pings to send ('nn')
'b' record stats in 'bbuuzzb' table (see below)
'q' run quietly
'p' host name or IP address to ping
'l' log name or destination
This program works by pinging a specific host (default host is used if
no host if specified using the 'p' switch. The results can be output to
the screen, to a log file, and/or to a database table using the 'bbuuzzb'
database. You may output to any combination of these three destinations.
Output to the 'bbuuzzb' database uses the table name listed in the global
constants. The data is stored where a single day is contained within a
record. The field layout is as follows:
field subfield subsubfield description
1 date (julian number)
2 * 1 time (24hr, no colon)
2 * 2 number of pings sent
2 * 3 number of pings successfully received
Since there is no support for 'exec' under MacOS, this program will
not run under MacOS.
Linux version based on original tcl program. Aug/2006, Rick Smereka */
#include "stdhead.h"
#include "flsocket.h"
#include "appinit.h"
#include "dbmess.h"
#include "dbiocode.h"
#include "dbcomm.h"
#ifdef MULTIUSER
#ifdef IPC_TCP
#include "socloc.h"
#include "sloc.h"
#include "slconfig.h"
#include "sliocode.h"
#ifdef OS_WIN32
WSADATA wsaData;
#endif
#endif
#endif
/* high level database API changes depending
on whether we are compiling for stand-alone
or multiuser */
#ifdef MULTIUSER
#include "dbcs.h"
#include "dbcscfg.h"
#else
#include "dbeng.h"
#include "dblocal.h"
#include "dbengcfg.h"
#include "dblocfg.h"
#endif
#define VERSION "1.21-2006.09.07"
#ifdef MULTIUSER
#define APNAME "ialivem"
#else
#define APNAME "ialive"
#endif
// #define DEBUG 1
#define DEFAULT_HOST "www.yahoo.com"
#define BBUUZZB_TABLE "ialive"
#define DEFAULT_LOG_FILE "ialive.log"
#define PING_OUTPUT_FILE "/work/logs/ping.log"
// database field and subsubfield definitions
#define FIELD_DATE 1
#define FIELD_PING_DATA 2
#define SUBSUBFIELD_TIME 1
#define SUBSUBFIELD_PINGS_SENT 2
#define SUBSUBFIELD_PINGS_RECV 3
// global variables
int tid;
char log_dest[128];
char ping_dest[128];
int log_output = FALSE;
int console_output = TRUE;
int ping_count = 4;
int use_bbuuzzb = FALSE;
// function prototypes
int main(int, char **);
void process(void);
void find_stats(char *);
int get_sent_recv(char *, int, int *);
int parse_comline(int, char **);
int c_initialize(void);
void app_out(char *,...);
void term_app(void);
#ifdef MULTIUSER
#ifdef IPC_TCP
int c_ipc_socloc_init(void);
#endif
#endif
int main(int argc, char **argv)
{
char mes[128], mname[] = "main";
int ret, lstatus;
/* parse command line */
if (!parse_comline(argc, argv))
return(0);
if (use_bbuuzzb)
{
// register application name with 'appinit'
if (!appinit_register_name(APNAME))
{
printf("%s:fatal error registering app name with appinit\n", APNAME);
return(0);
}
if (!c_initialize())
{
term_app();
return(0);
}
}
if (log_output)
{
if (logman_start(log_dest, APNAME))
{
printf("%s:unable to start log manager,program abort\n", APNAME);
return(0);
}
logman_console(console_output);
}
/* build logo string based on platform */
#ifndef OS_UNIX
/* non-Unix */
app_out("%s for %s Version %s", APNAME, PLATFORM_STRING,
VERSION);
#else
/* Unix */
app_out("%s for %s Version %s", APNAME, SUB_PLATFORM_STRING,
VERSION);
#endif
app_out("By Rick Smereka, Copyright (c) 2006");
app_out("%s comes with ABSOLUTELY NO WARRANTY", APNAME);
app_out("This is free software, and you are welcome to redistribute it");
app_out("under certain conditions; see 'gpl.txt' for information.");
if (logman_is_active())
{
app_out("%s:logging is on", APNAME);
app_out("%s:log name/destination is '%s'", APNAME, log_dest);
}
else
app_out("%s:logging is off");
app_out("%s:ping destination is '%s'", APNAME, ping_dest);
app_out("%s:ping count is %d", APNAME, ping_count);
(void)flag_2_logic_string(console_output, mes);
app_out("%s:console output is %s", APNAME, mes);
(void)flag_2_logic_string(use_bbuuzzb, mes);
app_out("%s:Bbuuzzb database mode is %s", APNAME, mes);
if (use_bbuuzzb)
app_out("%s:output Bbuuzzb table is %s", APNAME, BBUUZZB_TABLE);
process();
term_app();
return(0);
}
void process(void)
{
/* Execute the 'ping' command sending all program output to an
output file. Read back the 'ping' output file to determine
the response and possibly record the response in the
'bbuuzzb' table. */
char line[75], curdatime[15], curdate[9], curtime[5], mname[] = "process";
char wrd[50];
int ret, subfield, pings_sent, pings_recv;
// build the command line
#ifdef OS_UNIX
sprintf(line, "ping -c %d %s >%s", ping_count, ping_dest, PING_OUTPUT_FILE);
#else
sprintf(line, "ping -n %d %s >%s", ping_count, ping_dest, PING_OUTPUT_FILE);
#endif
// execute the command
app_out("%s:command=%s", mname, line);
(void)system(line);
// locate the stats line in the ping output file
find_stats(line);
if (!strlen(line))
{
// if there is no output from the 'ping' command, assume process gave up
app_out("%s:output 'ping' line is empty,assuming nothing received",
mname);
// mock-up output line
sprintf(line, "sent %d,recv 0", ping_count);
}
app_out("%s:line=%s", mname, line);
if (!use_bbuuzzb)
return;
/* store sent and received stats in daily record
get the date and time now, use the hour and minute in the record and
convert the date to julian */
get_time(curdatime);
strncpy(curtime, &curdatime[8], 4);
curtime[4] = EOS;
strncpy(curdate, curdatime, 8);
curdate[8] = EOS;
if ((ret = db_open(BBUUZZB_TABLE, &tid)) != DBENG_OK)
{
app_out("%s:unable to open table '%s'", mname, BBUUZZB_TABLE);
return;
}
// attempt to locate existing record, if not present, create new record
if ((ret = db_find_field(tid, 0, curdate, FIELD_DATE)) != DBENG_OK)
{
if (ret == DBENG_EOF)
{
app_out("%s:daily record does not exist,creating it", mname);
if ((ret = db_new(tid)) != DBENG_OK)
{
app_out("%s:bad rc[%d] from db_new", mname, ret);
return;
}
if ((ret = db_put_field(tid, FIELD_DATE, curdate)) != DBENG_OK)
{
app_out("%s:bad rc[%d] from db_put_field[date]", mname, ret);
return;
}
subfield = 1;
}
else
{
app_out("%s:bad rc[%d] from db_find_field[date]", mname, ret);
return;
}
}
else
{
if ((ret = db_get_nsubfields(tid, FIELD_PING_DATA, &subfield))
!= DBENG_OK)
{
app_out("%s:bad rc[%d] from db_get_nsubfields", mname, ret);
return;
}
subfield++;
}
// new subfields is assed onto the end of the list
if ((ret = db_put_subsubfield(tid, FIELD_PING_DATA, subfield,
SUBSUBFIELD_TIME, curtime)) != DBENG_OK)
{
app_out("%s:bad rc[%d] from db_put_subsubfield[time]", mname, ret);
return;
}
/* extract send and received stats from ping output
method chosen works on all platforms by grabbing
the first number in the first two (comma delimited)
words on the line */
if (!get_sent_recv(line, 1, &pings_sent))
return;
if (!get_sent_recv(line, 2, &pings_recv))
return;
// put the rest of the table data and write
sprintf(wrd, "%d", pings_sent);
if ((ret = db_put_subsubfield(tid, FIELD_PING_DATA, subfield,
SUBSUBFIELD_PINGS_SENT, wrd)) != DBENG_OK)
{
app_out("%s:bad rc[%d] from db_put_subsubfield[pings_sent]", mname, ret);
return;
}
sprintf(wrd, "%d", pings_recv);
if ((ret = db_put_subsubfield(tid, FIELD_PING_DATA, subfield,
SUBSUBFIELD_PINGS_RECV, wrd)) != DBENG_OK)
{
app_out("%s:bad rc[%d] from db_put_subsubfield[pings_recv]", mname, ret);
return;
}
if ((ret = db_write(tid)) != DBENG_OK)
{
app_out("%s:bad rc[%d] from db_write", mname, ret);
return;
}
app_out("%s:curdate=%s,curtime=%s,subfield=%d", mname, curdate, curtime,
subfield);
app_out("%s:pings_sent=%d,pings_recv=%d", mname, pings_sent, pings_recv);
}
void find_stats(char *line)
{
/* Locate the line containing the stats. Returns the line containing
the send and receive status (in 'line') upon success, an empty
string otherwise. */
FILE *in;
char buf[128], mname[] = "find_stats";
int nwords;
line[0] = EOS;
// open 'ping' output file
if ((in = fopen(PING_OUTPUT_FILE, "r")) == (FILE *)NULL)
{
app_out("%s:unable to open ping output file '%s'",
mname, PING_OUTPUT_FILE);
return;
}
/* read each line looking for the stats line (the first line with at
least two comma delimited words) */
get_rec(in, buf);
while(!feof(in))
{
nwords = ll_words(buf, ',');
if (nwords > 1)
{
strcpy(line, buf);
fclose(in);
return;
}
get_rec(in, buf);
}
fclose(in);
}
int get_sent_recv(char *line, int which, int *result)
{
/* Get the sent or received stats from the ping data. Returns 'TRUE'
upon success with the result loaded into 'result', returns
'FALSE' otherwise. */
char parm[50], wrd[50], mname[] = "get_sent_recv";
int nwords, i, tmp;
*result = 0;
if (!ll_word(line, parm, which, ','))
{
app_out("%s:bad rc(0) from ll_word[line(%d)]", mname, which);
return(FALSE);
}
trim(parm, wrd);
strcpy(parm, wrd);
nwords = words(parm);
for(i = 1; i <= nwords; i++)
{
if (!word(parm, wrd, i))
{
app_out("%s:bad rc[0] from word[%d]", mname, i);
return(FALSE);
}
if (qatoi(wrd, &tmp))
{
*result = tmp;
return(TRUE);
}
}
app_out("%s:exit[0],count not found", mname);
return(FALSE);
}
int parse_comline(int c_count, char **c_parm)
{
/* Parse the command line for parameters. Function
returns 'TRUE' if no error was detected, 'FALSE'
otherwise. */
char mname[] = "parse_comline", tmp[25];
int parms = 1, done = FALSE;
/* set default log file */
strcpy(log_dest, DEFAULT_LOG_FILE);
strcpy(ping_dest, DEFAULT_HOST);
if (c_count == 1)
done = TRUE;
while(!done)
{
if (c_parm[parms][0] == SWITCH_CHAR)
{
switch(toupper(c_parm[parms][1]))
{
case 'L':
if (strlen(c_parm[parms]) > 2)
printf("%s:%s:extraneous input with log switch, "
"ignoring\n", APNAME, mname);
parms++;
if (c_count > parms)
strcpy(log_dest, c_parm[parms++]);
log_output = TRUE;
break;
case 'C':
if (strlen(c_parm[parms]) > 2)
printf("%s:%s:extraneous input with ping count switch, "
"ignoring\n", APNAME, mname);
parms++;
if (c_count <= parms)
{
printf("%s:%s:'c' switch present without ping count,"
"program abort\n", APNAME, mname);
return(FALSE);
}
strcpy(tmp, c_parm[parms++]);
if (!qatoi(tmp, &ping_count))
{
printf("%s:%s:non-numeric ping count,program abort\n",
APNAME, mname);
return(FALSE);
}
if (ping_count < 1)
{
printf("%s:%s:out of range ping count,s/b >0,abort\n",
APNAME, mname);
return(FALSE);
}
break;
case 'B':
use_bbuuzzb = TRUE;
parms++;
break;
case 'Q':
console_output = FALSE;
parms++;
break;
case 'P':
if (strlen(c_parm[parms]) > 2)
printf("%s:%s:extraneous input with ping destination switch, "
"ignoring\n", APNAME, mname);
parms++;
if (c_count <= parms)
{
printf("%s:%s:'p' switch present without ping destination,"
"program abort\n", APNAME, mname);
return(FALSE);
}
strcpy(ping_dest, c_parm[parms++]);
break;
default:
printf("%s:%s:unknown switch[%s],program abort\n",
APNAME, mname, c_parm[parms]);
return(FALSE);
};
}
if (parms >= c_count)
done = TRUE;
}
return(TRUE);
}
#ifdef MULTIUSER
int c_initialize(void)
{
/* Initialize socket communication, form connection to
'socloc' server (TCP only), update the config list and connect
to a 'Bbuuzzb' server. Function returns 'TRUE' upon
success, 'FALSE' otherwise. */
char mname[] = "c_initialize";
char mes[128];
int ret;
#ifdef IPC_TCP
if (!c_ipc_socloc_init())
return(FALSE);
#endif
/* attempt to locate a 'Bbuuzzb' server and connect to it */
if ((ret = db_initialize()) != DBENG_OK)
{
db_io_code_string(ret, mes);
printf("%s:error connecting to the Bbuuzzb server,rc[%s]. "
"Program abort\n", mname, mes);
return(FALSE);
}
/* display current connected server host name and
TCP port number */
#ifdef IPC_TCP
(void)db_get_active(mes, &ret);
printf("%s:connected to Bbuuzzb server %s on TCP port %d (decimal)\n",
mname, mes, ret);
#endif
return(TRUE);
}
#endif
#ifndef MULTIUSER
int c_initialize(void)
{
/* Start the 'DBENG' local engine, read the config file
and display the result settings. Function returns
'TRUE' upon success, 'FALSE' otherwise. */
char mname[] = "c_initialize";
char *mes;
int ret, flag;
#ifdef DEBUG
#ifdef IPC_TCP
if (!c_ipc_socloc_init())
return(FALSE);
#endif
#endif
if ((mes = (char *)malloc(DBENG_PATH_LIMIT)) == (char *)NULL)
{
printf("%s:alloc fail[mes]. Program abort\n", mname);
return(FALSE);
}
ret = db_initialize();
/* interpret code from init which may be
a fatal config error */
switch(ret)
{
case DBENG_OK:
printf("%s:read config file successfully\n", mname);
break;
case DBENG_CONFIG_UNABLE_TO_OPEN:
printf("%s:config file not found, loaded defaults\n", mname);
break;
default:
db_io_code_string(ret, mes);
printf("%s:fatal config error[%s]\n", mname, mes);
printf("%s:terminating\n", mname);
free(mes);
return(FALSE);
break;
};
(void)db_config_get_tmp_path(mes);
printf("%s:tmp path is '%s'\n", mname, mes);
(void)db_config_get_log(mes);
printf("%s:log is '%s'\n", mname, mes);
if ((ret = db_config_get_catalog(mes)) == DBENG_OK)
printf("%s:catalog is '%s'\n", mname, mes);
else
printf("%s:catalog name not loaded\n", mname);
(void)db_config_get_catalog_flag(&flag);
if (flag_2_logic_string(flag, mes))
printf("%s:catalog is %s\n", mname, mes);
free(mes);
return(TRUE);
}
#endif
#ifdef MULTIUSER
#ifdef IPC_TCP
int c_ipc_socloc_init(void)
{
/* Initialize socket communication, form connection to
'socloc' server (TCP only) and update the config list.
Function returns 'TRUE' upon success, 'FALSE' otherwise. */
char mname[] = "c_ipc_socloc_init";
char *thelist, mes[128];
int ret;
/* startup WinSock (if Windoze) */
#ifdef OS_WIN32
if (WSAStartup(WINSOCK_VERSION, &wsaData))
{
printf("%s:unable to start WinSock. "
"Program abort\n", mname);
return(FALSE);
}
#endif
/* attempt to connect to a 'socloc' server */
if ((ret = sloc_initialize()) != SL_OK)
{
sl_code_string(ret, mes);
printf("%s:error initializing socloc interface,rc[%s]. "
"Program abort\n", mname, mes);
return(FALSE);
}
/* get config list from 'socloc' server and update
the client list with it */
if ((thelist = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
{
printf("%s:alloc fail[thelist]. Program abort\n", mname);
return(FALSE);
}
if ((ret = sloc_config_get_list(thelist)) != SL_OK)
{
free(thelist);
sl_code_string(ret, mes);
printf("%s:error getting socloc config list,rc[%s]. "
"Program abort\n", mname, mes);
return(FALSE);
}
if ((ret = sl_config_put_list(thelist)) != SL_OK)
{
sl_code_string(ret, mes);
printf("%s:error putting socloc config list,rc[%s]. ",
"Program abort\n", mname, mes);
free(thelist);
return(FALSE);
}
free(thelist);
return(TRUE);
}
#endif
#endif
void app_out(char *fmt,...)
{
/* Output a message to the console and/or the log file. */
va_list argptr;
char *mes, mname[] = "app_out";
int ret;
/* if no output, return */
if (!console_output && !log_output)
return;
va_start(argptr, fmt);
if ((mes = (char *)malloc(BUFSIZE)) == (char *)NULL)
{
logman("%s:%s:alloc fail[mes]", APNAME, mname);
return;
}
/* format message */
memset(mes, 0, BUFSIZE);
vsprintf(mes, fmt, argptr);
if (log_output)
logman_nf(mes);
if (!log_output && console_output)
printf("%s\n", mes);
free(mes);
}
void term_app(void)
{
// Prepare to terminate the application. Shutdown all IPC API's.
if (logman_is_active())
logman_end();
if (use_bbuuzzb)
{
(void)db_close(tid);
db_end();
#ifdef MULTIUSER
#ifdef IPC_TCP
if (sloc_is_init())
sloc_term_api();
#ifdef OS_WIN32
WSACleanup();
#endif
#endif
#endif
(void)appinit_remove_name();
}
}