Turn on self-spawning: main loop should never crash but exists only to

respawn child when it does.  Add crash command to test this.  Add
ability to set logging level from ctrl port.
This commit is contained in:
ehouse 2007-11-10 05:41:49 +00:00
parent 6db5eed156
commit 0291ec1e75
8 changed files with 106 additions and 31 deletions

View file

@ -28,7 +28,7 @@ SRC = xwrelay.cpp \
OBJ = $(patsubst %.cpp,%.o,$(SRC))
LDFLAGS += -pthread -g -lmcheck
CPPFLAGS += -g -Wall -DSVN_REV=\"$(shell svnversion -n .)\"
CPPFLAGS += -DSPAWN_SELF -g -Wall -DSVN_REV=\"$(shell svnversion -n .)\"
# turn on semaphore debugging
# CPPFLAGS += -DDEBUG_LOCKS

View file

@ -41,7 +41,6 @@ RelayConfigs* RelayConfigs::instance = NULL;
/* static */ RelayConfigs*
RelayConfigs::GetConfigs()
{
assert( instance != NULL );
return instance;
}
@ -107,6 +106,8 @@ RelayConfigs::parse( const char* fname )
m_serverName = value;
} else if ( 0 == strcmp( line, "IDFILE" ) ) {
m_idFileName = value;
} else if ( 0 == strcmp( line, "LOGLEVEL" ) ) {
m_logLevel = atoi(value);
} else {
logf( XW_LOGERROR, "unknown key %s with value %s\n",
line, value );

View file

@ -39,6 +39,8 @@ class RelayConfigs {
time_t GetHeartbeatInterval() { return m_heartbeatInterval; }
const char* GetServerName() { return m_serverName.c_str(); }
const char* GetIdFileName() { return m_idFileName.c_str(); }
int GetLogLevel(void) { return m_logLevel; }
void SetLogLevel(int ll) { m_logLevel = ll; }
private:
RelayConfigs( const char* cfile );
@ -48,6 +50,7 @@ class RelayConfigs {
time_t m_heartbeatInterval;
int m_ctrlport;
int m_port;
int m_logLevel;
int m_nWorkerThreads;
std::string m_serverName;
std::string m_idFileName;

View file

@ -43,10 +43,12 @@
#include "crefmgr.h"
#include "mlock.h"
#include "xwrelay_priv.h"
#include "configs.h"
/* this is *only* for testing. Don't abuse!!!! */
extern pthread_rwlock_t gCookieMapRWLock;
/* Return of true means exit the ctrl thread */
typedef bool (*CmdPtr)( int socket, const char** args );
typedef struct FuncRec {
@ -70,6 +72,7 @@ static bool cmd_set( int socket, const char** args );
static bool cmd_shutdown( int socket, const char** args );
static bool cmd_rev( int socket, const char** args );
static bool cmd_uptime( int socket, const char** args );
static bool cmd_crash( int socket, const char** args );
static void
print_to_sock( int sock, bool addCR, const char* what, ... )
@ -102,6 +105,7 @@ static const FuncRec gFuncs[] = {
{ "set", cmd_set },
{ "rev", cmd_rev },
{ "uptime", cmd_uptime },
{ "crash", cmd_crash },
};
static bool
@ -110,9 +114,11 @@ cmd_quit( int socket, const char** args )
if ( 0 == strcmp( "help", args[1] ) ) {
print_to_sock( socket, true, "* %s (disconnect from ctrl port)",
args[0] );
return false;
} else {
print_to_sock( socket, true, "bye bye" );
return true;
}
return 0;
}
static void
@ -136,14 +142,14 @@ static bool
cmd_start( int socket, const char** args )
{
print_to_sock( socket, true, "* %s (unimplemented)", args[0] );
return 1;
return false;
}
static bool
cmd_stop( int socket, const char** args )
{
print_to_sock( socket, true, "* %s (unimplemented)", args[0] );
return 1;
return false;
}
static bool
@ -185,24 +191,50 @@ cmd_kill_eject( int socket, const char** args )
;
print_to_sock( socket, true, msg, args[0], expl, args[0], args[0] );
}
return 1;
return false;
} /* cmd_kill_eject */
static bool
cmd_get( int socket, const char** args )
{
print_to_sock( socket, true,
"* %s -- lists all attributes (unimplemented)\n"
"* %s <attribute> (unimplemented)",
args[0], args[0] );
return 1;
if ( 0 == strcmp( args[1], "help" ) ) {
print_to_sock( socket, true,
"* %s -- lists all attributes (unimplemented)\n"
"* %s loglevel",
args[0], args[0] );
} else {
const char* attr = args[1];
if ( (NULL != attr) && (0 == strcmp( attr, "loglevel" )) ) {
RelayConfigs* rc = RelayConfigs::GetConfigs();
if ( NULL != rc ) {
print_to_sock( socket, true, "loglevel=%d\n",
rc->GetLogLevel() );
} else {
logf( XW_LOGERROR, "RelayConfigs::GetConfigs() => NULL" );
}
}
}
return false;
}
static bool
cmd_set( int socket, const char** args )
{
print_to_sock( socket, true, "* %s <attribute> (unimplemented)", args[0] );
return 1;
if ( 0 == strcmp( args[1], "help" ) ) {
print_to_sock( socket, true, "* %s loglevel <n>\n", args[0] );
} else {
const char* attr = args[1];
const char* val = args[2];
if ( (NULL != attr)
&& (0 == strcmp( attr, "loglevel" ))
&& (NULL != val) ) {
RelayConfigs* rc = RelayConfigs::GetConfigs();
if ( rc != NULL ) {
rc->SetLogLevel( atoi(val) );
}
}
}
return false;
}
static bool
@ -215,7 +247,7 @@ cmd_rev( int socket, const char** args )
} else {
print_to_sock( socket, true, "svn rev: %s", SVN_REV );
}
return 0;
return false;
}
static bool
@ -241,7 +273,23 @@ cmd_uptime( int socket, const char** args )
"uptime: %d days, %d hours, %d minutes, %ld seconds",
days, hours, minutes, seconds );
}
return 0;
return false;
}
static bool
cmd_crash( int socket, const char** args )
{
if ( 0 == strcmp( args[1], "help" ) ) {
print_to_sock( socket, true,
"* %s -- fires an assert (debug case) or divides-by-zero",
args[0] );
} else {
assert(0);
int i = 1;
while ( i > 0 ) --i;
return 6/i > 0;
}
return false;
}
static bool
@ -250,7 +298,7 @@ cmd_shutdown( int socket, const char** args )
print_to_sock( socket, true,
"* %s -- shuts down relay (exiting main) (unimplemented)",
args[0] );
return 1;
return false;
}
static void

View file

@ -81,6 +81,10 @@ StateTable g_stateTable[] = {
{ XWS_CONNECTING, XWE_DISCONNMSG, XWA_DISCONNECT, XWS_CONNECTING },
{ XWS_MISSING, XWE_DISCONNMSG, XWA_DISCONNECT, XWS_MISSING },
/* I'm seeing this but not sure how to handle. Might disconnect be
needed now */
{ XWS_MISSING, XWE_FORWARDMSG, XWA_DISCONNECT, XWS_MISSING },
{ XWS_ANY, XWE_NOMORESOCKETS, XWA_NONE, XWS_DEAD },
{ XWS_ANY, XWE_SHUTDOWN, XWA_SHUTDOWN, XWS_DEAD },
@ -115,33 +119,36 @@ StateTable g_stateTable[] = {
/* This is our bread-n-butter */
{ XWS_ALLCONNECTED, XWE_FORWARDMSG, XWA_FWD, XWS_ALLCONNECTED },
{ XWS_DEAD, XWE_REMOVESOCKET, XWA_REMOVESOCKET, XWS_DEAD },
{ XWS_DEAD, XWE_REMOVESOCKET, XWA_REMOVESOCKET, XWS_DEAD }
/* Marks end of table */
{ XWS_NONE, XWE_NONE, XWA_NONE, XWS_NONE }
};
int
bool
getFromTable( XW_RELAY_STATE curState, XW_RELAY_EVENT curEvent,
XW_RELAY_ACTION* takeAction, XW_RELAY_STATE* nextState )
{
bool found = false;
StateTable* stp = g_stateTable;
while ( stp->stateStart != XWS_NONE ) {
const StateTable* end = stp + sizeof(g_stateTable)/sizeof(g_stateTable[0]);
while ( stp < end ) {
if ( stp->stateStart == curState || stp->stateStart == XWS_ANY ) {
if ( stp->stateEvent == curEvent || stp->stateEvent == XWE_ANY ) {
*takeAction = stp->stateAction;
*nextState = stp->stateEnd;
return 1;
found = true;
break;
}
}
++stp;
}
logf( XW_LOGERROR, "==> ERROR :: unable to find transition from %s on event %s",
stateString(curState), eventString(curEvent) );
return 0;
if ( !found ) {
logf( XW_LOGERROR, "==> ERROR :: unable to find transition from %s "
"on event %s",
stateString(curState), eventString(curEvent) );
}
return found;
} /* getFromTable */
#define CASESTR(s) case s: return #s

View file

@ -149,8 +149,8 @@ typedef enum {
} XW_RELAY_ACTION;
int getFromTable( XW_RELAY_STATE curState, XW_RELAY_EVENT curEvent,
XW_RELAY_ACTION* takeAction, XW_RELAY_STATE* nextState );
bool getFromTable( XW_RELAY_STATE curState, XW_RELAY_EVENT curEvent,
XW_RELAY_ACTION* takeAction, XW_RELAY_STATE* nextState );
char* stateString( XW_RELAY_STATE state );

View file

@ -26,4 +26,8 @@ SERVERNAME=eehouse.org
# Where will the file live that stores the last ID used for a new
# connName.
#IDFILE=/home/ehouse/xwrelay_id.txt
IDFILE=/home/eehouse/xwrelay_id.txt
# Initial level of logging. See xwrelay_priv.h for values. Currently
# 0 means errors only, 1 info, 2 verbose and 3 very verbose.
LOGLEVEL=0

View file

@ -73,7 +73,8 @@
void
logf( XW_LogLevel level, const char* format, ... )
{
if ( level <= XW_LOGINFO ) {
RelayConfigs* rc = RelayConfigs::GetConfigs();
if ( NULL == rc || level <= rc->GetLogLevel() ) {
FILE* where = stderr;
struct tm* timp;
struct timeval tv;
@ -376,6 +377,16 @@ static int
make_socket( unsigned long addr, unsigned short port )
{
int sock = socket( AF_INET, SOCK_STREAM, 0 );
assert( sock );
/* We may be relaunching after crashing with sockets open. SO_REUSEADDR
allows them to be immediately rebound. */
int t = true;
if ( 0 != setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &t, sizeof(t) ) ) {
logf( XW_LOGERROR, "setsockopt failed. errno = %s (%d)\n",
strerror(errno), errno );
return -1;
}
struct sockaddr_in sockAddr;
sockAddr.sin_family = AF_INET;
@ -543,6 +554,8 @@ int main( int argc, char** argv )
PermID::SetServerName( serverName );
PermID::SetIDFileName( idFileName );
/* add signal handling here */
#ifdef SPAWN_SELF
/* loop forever, relaunching children as they die. */
for ( ; ; ) {
@ -554,7 +567,6 @@ int main( int argc, char** argv )
logf( XW_LOGINFO, "parent waiting on child pid=%d", pid );
waitpid( pid, &status, 0 );
printWhy( status );
sleep( 45 ); /* give time to close sockets? */
} else {
logf( XW_LOGERROR, "fork() => %s", strerror(errno) );
}