/* * This file is part of rasdaman community. * * Rasdaman community 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 3 of the License, or * (at your option) any later version. * * Rasdaman community 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 rasdaman community. If not, see . * * Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / rasdaman GmbH. * * For more information please see * or contact Peter Baumann via . / /** * SOURCE: rasmgr_srv.cc * * MODULE: rasmgr * CLASS: RasServer, RasServerManager * * COMMENTS: * None */ #include "rasmgr_srv.hh" #include "rasmgr_localsrv.hh" #include "rasmgr_comm.hh" #include "rasmgr_users.hh" #include "debug.hh" // host name returned when we don't have a valid one: #define NO_VALID_HOST "noValidHost" // initial countdown value #define INITIAL_COUNTDOWN 1000 RasServer::RasServer() { serverName[0]=0; extraParam[0]=0; ptrServerHost=NULL; ptrDatabaseHost=NULL; //connStr[0]=0; available=isup=isstarting=false; valid=false; downReq=false; initialCountDown = INITIAL_COUNTDOWN; currentCountDown = INITIAL_COUNTDOWN; // asa doreste management writeTransaction=false; // no clearTransaction!! readTransaction=false; connDatabase = NULL; activityExpected=false; crashCount = 0; activityCounter = 0; // will be changed in init() autorestart = true; strcpy(executableName,RASEXECUTABLE); } RasServer::~RasServer() { } const char* RasServer::getName() { return serverName; } const char* RasServer::getHostName() { if(ptrServerHost) { return ptrServerHost->getName(); } return NO_VALID_HOST; } const char* RasServer::getHostNetwName() { if(ptrServerHost) { return ptrServerHost->getNetworkName(); } return NO_VALID_HOST; } long RasServer::getPort() { return listenPort; } char RasServer::getType() { return serverType; } void RasServer::changeName(const char *newName) { // FIXME: input parameter validity check! strncpy( serverName, newName, sizeof(serverName) ); } void RasServer::changeType(const char newType) // char not char*!! // FIXME: input parameter validity check! { serverType=newType; } void RasServer::changePort(long newPort) { listenPort=newPort; } void RasServer::changeExtraParam(const char *xParam) // FIXME: input parameter validity check! { strncpy(extraParam,xParam,sizeof(extraParam) ); } void RasServer::changeCountDown(int newCountDown) { initialCountDown=newCountDown; currentCountDown=newCountDown; } void RasServer::changeAutoRestart(bool x) { autorestart = x; } const char* RasServer::getExtraParams() { return extraParam; } int RasServer::getCountDown() { return initialCountDown; } void RasServer::init(const char *srvName,const char* hostName,char serverType,long listenPort) { strcpy(this->serverName,srvName); ptrServerHost=&hostmanager[hostName];// should be valid! isinternal=ptrServerHost->isInternal(); available=isup=false; this->serverType=serverType; this->listenPort=listenPort; // RNP servers start with first action connectToDBMS() as opposed to the others, // therefore set counter appropriately. -- PB 2002-nov-23 switch (serverType) { case SERVERTYPE_FLAG_RPC: case SERVERTYPE_FLAG_HTTP: TALK( "Initializing activity counter to 1 for RPC/HTTP type server." ); activityCounter = 1; break; case SERVERTYPE_FLAG_RNP: TALK( "Initializing activity counter to 0 for RNP type server." ); activityCounter = 0; break; default: TALK( "Error: illegal server type specifier " << serverType << ", assuming '" << SERVERTYPE_FLAG_RNP << "'." ); break; } valid=true; } bool RasServer::isValid() { return valid; } bool RasServer::isUp() { return isup; } bool RasServer::isStarting() { return isstarting; } bool RasServer::isAvailable() { return available; } bool RasServer::forceAvailable() { // this function is just for advanced system debug, not for production work if(isup) { available=true; clearPendingTransaction(); return true; } return false; } void RasServer::setNotAvailable() { available=false; regularSignalCounter = MAXREGULARCOUNTER; } bool RasServer::isAutoRestart() { return autorestart; } char* RasServer::getDescriptionHeader(char *destBuffer) { sprintf(destBuffer," %-20s %s %-20s %-20s %-4s %-2s %s %s","Server Name","Type","Host","Db Host","Stat","Av","Acc","Crc"); return destBuffer; } char* RasServer::getDescription(char *destBuffer) { char *sType="(none)"; if(serverType==SERVERTYPE_FLAG_RPC) sType="(RPC) "; if(serverType==SERVERTYPE_FLAG_HTTP) sType="(HTTP)"; if(serverType==SERVERTYPE_FLAG_RNP) sType="(RNP) "; const char* sUp= isup ? "UP ":"DOWN"; const char* sAv= available ? "YES":"NO "; const char* host= ptrServerHost->getName();//"(internal)"; const char* dbHost = getDBHostName(); //if(isinternal==false) // { host=ptrServerHost->getName(); // } sprintf(destBuffer,"%-20s %s %-20s %-20s %s %s %6ld %2d",serverName,sType,host,dbHost,sUp,sAv,activityCounter,crashCount); return destBuffer; } char* RasServer::getDescriptionPortHeader(char *destBuffer) { sprintf(destBuffer," %-20s %s %-20s %-10s %-3s %-3s","Server Name","Type","Host"," Port","Ars"," Icd"); return destBuffer; } char* RasServer::getDescriptionPort(char *destBuffer) { char *sType="(none)"; if(serverType==SERVERTYPE_FLAG_RPC) sType="(RPC) "; if(serverType==SERVERTYPE_FLAG_HTTP) sType="(HTTP)"; if(serverType==SERVERTYPE_FLAG_RNP) sType="(RNP) "; // const char* sUp= isup ? "UP ":"DOWN"; // const char* sAv= available ? "YES":"NO "; const char* host = ptrServerHost->getName(); const char *ars = autorestart ? "on":"off"; if(serverType==SERVERTYPE_FLAG_RPC) sprintf(destBuffer,"%-20s %s %-20s %#10lx %-3s %3d/%-3d",serverName,sType,host,listenPort,ars,currentCountDown,initialCountDown); else sprintf(destBuffer,"%-20s %s %-20s %10ld %-3s %3d/%-3d",serverName,sType,host,listenPort,ars,currentCountDown,initialCountDown); //countdown=%d InitialCountDown, return destBuffer; } char* RasServer::getDescriptionExecHeader(char *destBuffer) { sprintf(destBuffer," %-20s %-10s Executable Extraparameters","Server Name","Host"); return destBuffer; } char* RasServer::getDescriptionExec(char *destBuffer) { const char* host = ptrServerHost->getName(); sprintf(destBuffer,"%-20s %-10s %-15s %s",serverName,host,executableName,extraParam); return destBuffer; } bool RasServer::connectToDBHost(const char *dbHostName)//, const char *connString) { if(ptrDatabaseHost) return false; DatabaseHost &dbh=dbHostManager[dbHostName]; if(dbh.isValid()==false) return false; ptrDatabaseHost = &dbh; //removed dbh.incrConnServers(); //strcpy(connStr,connString); for(int i=0;igetName(); for(int i=0;idecrConnServers(); ptrDatabaseHost=NULL; return true; } const char* RasServer::getDBHostName() { if(ptrDatabaseHost) return ptrDatabaseHost->getName(); return "noDBHost!"; } bool RasServer::isConnectedToDBHost() { if(ptrDatabaseHost) return true; return false; } void RasServer::changeExecutableName(const char *newExecutable) { if(newExecutable == NULL) strcpy(executableName,RASEXECUTABLE); else strcpy(executableName,newExecutable); } const char* RasServer::getExecutableName() { return executableName; } int RasServer::startServerInDebugger(char *command) { if(ptrDatabaseHost==NULL) return RASSERVER_NODATABASEHOST; if(ptrServerHost->isUp()==false) return RASSERVER_SRVNOTUP; downReq=false; const char *sTypeString= serverType==SERVERTYPE_FLAG_HTTP ? "--http":""; const char *rasmgrHost = ptrServerHost->useLocalHost() ? "localhost" : config.getHostName(); sprintf(command, "%s --rsn %s %s --lport %ld ",executableName,serverName,sTypeString,listenPort); sprintf(command+strlen(command),"--mgr %s --mgrport %d --connect %s ",rasmgrHost,config.getListenPort(),ptrDatabaseHost->getConnectionString()); sprintf(command+strlen(command),"--sync %s %s",authorization.getSyncroString(),extraParam); currentCountDown=initialCountDown; activityExpected=true; activityCounter = 0; TALK( "RasServer::startServerInDebugger() -> " << command ); return RASSERVER_OK; } int RasServer::startServer() { if(ptrDatabaseHost==NULL) return RASSERVER_NODATABASEHOST; if(ptrServerHost->isUp()==false) return RASSERVER_SRVNOTUP; downReq=false; const char *sTypeString= serverType==SERVERTYPE_FLAG_HTTP ? "--http" : ""; sTypeString= serverType==SERVERTYPE_FLAG_RNP ? "--rnp" : sTypeString; const char *rasmgrHost = ptrServerHost->useLocalHost() ? "localhost" : config.getHostName(); char command[MAX_CMD_LEN+1]; const char *SPRINTF_FORMAT = "%s %s %s --rsn %s %s --lport %ld --mgr %s --mgrport %ld --connect %s %s"; // check for buffer oflo unsigned int commandLen = strlen(SPRINTF_FORMAT) + strlen(serverName) + strlen(executableName) + strlen(executableName) + strlen(serverName) + strlen(sTypeString) + 4 // aka strlen(listenPort) + strlen(rasmgrHost) + 4 // aka strlen(config.getListenPort()) + strlen(ptrDatabaseHost->getConnectionString()) + strlen(extraParam); if (commandLen > MAX_CMD_LEN) { TALK( "RasServer::startServer(): fatal error: command line can host " << MAX_CMD_LEN << " bytes, but needs " << commandLen << "." ); std::cout<<"Error: rasserver command line too long, cannot launch. Disappointedly aborting server start." <getConnectionString(), extraParam); if(isinternal) { TALK( "launching local server, command=" << command ); localServerManager.startNewServer(command); } else { TALK( "connecting to remote rasmgr" ); int socket=ptrServerHost->getConnectionSocket(); if(socket<0) return RASSERVER_NOREMOTERASMGR; char message[MAXMSG]="POST exec HTTP/1.1\r\nAccept: text/plain\r\nUserAgent: RasMGR/1.0\r\nContent-length: "; sprintf(message+strlen(message),"%d\r\n\r\n%s",strlen(command)+1,command); int nbytes=write(socket,message,strlen(message)+1); close(socket); if(nbytes<0) return RASSERVER_INCOMPLETESEND; } currentCountDown=initialCountDown; activityExpected=true; isstarting=true; activityCounter = 0; return RASSERVER_OK; } int RasServer::downServer(bool forced) { if(available==false && (forced == false || isstarting==true) ) { downReq=true; //std::cout<<"Down request, but working"<getConnectionSocket(); if(socket<0) return RASSERVER_CANNOTSTARTSRV; char message[MAXMSG]="POST downserver HTTP/1.1\r\nAccept: text/plain\r\nUserAgent: RasMGR/1.0\r\nContent-length: "; sprintf(message+strlen(message),"%d\r\n\r\n%s",strlen(serverName)+1,serverName); int nbytes=write(socket,message,strlen(message)+1); close(socket); if(nbytes<0) return RASSERVER_NOREMOTERASMGR; // FIXME: should be RASSERVER_INCOMPLETESEND? } //ptrServerHost->regDownServer(); return RASSERVER_OK; } int RasServer::killServer() { if(isup) { ptrServerHost->regDownServer(); if(ptrDatabaseHost) ptrDatabaseHost->regDownServer(); isup=available=0; activityExpected=false; } if(isinternal) { localServerManager.killServer(serverName); } else { int socket=ptrServerHost->getConnectionSocket(); if(socket<0) return RASSERVER_CANNOTSTARTSRV; char message[MAXMSG]="POST killserver HTTP/1.1\r\nAccept: text/plain\r\nUserAgent: RasMGR/1.0\r\nContent-length: "; sprintf(message+strlen(message),"%d\r\n\r\n%s",strlen(serverName)+1,serverName); int nbytes=write(socket,message,strlen(message)+1); close(socket); if(nbytes<0) return RASSERVER_NOREMOTERASMGR; // FIXME: should be RASSERVER_INCOMPLETESEND? } return RASSERVER_OK; } void RasServer::changeStatus(int newStatus,long infCount) { ENTER( "RasServer::changeStatus: enter. servername="<1 && autorestart) { // a crashed server doesn't autorestart if it crashes before starting work. TALK( "auto restart activated, restarting." ); startServer(); } } // commented out due to some error if(initialCountDown) { TALK( "rasmgr: initialCountDown is " << initialCountDown ); if(available) { TALK( "rasmgr: " << serverName << " is available." ); currentCountDown--; if(currentCountDown==0) { available=false; TALK( "rasmgr: Countdown reached for "<endWriteTransaction(); if(readTransaction ) connDatabase->endReadTransaction(); writeTransaction=false; readTransaction =false; connDatabase = NULL; } //********************************************************************** RasServerManager::RasServerManager() { } RasServerManager::~RasServerManager() { } bool RasServerManager::insertNewServer(const char *srvName,const char* hostName,char serverType,long listenPort) { bool result = true; if(testUniqueness(srvName)==false) result = false; if( result == true && hostmanager[hostName].isValid()==false) result = false; if(result == true && serverType!=SERVERTYPE_FLAG_RPC && serverType!=SERVERTYPE_FLAG_HTTP && serverType!=SERVERTYPE_FLAG_RNP) { TALK( "RasServerManager::insertNewServer: server " << srvName << " has illegal type " << serverType ); result = false; } if (result == true) { RasServer tempRasServer; srvList.push_back(tempRasServer); RasServer &refRasServer=srvList.back(); refRasServer.init(srvName,hostName,serverType,listenPort); } return result; } bool RasServerManager::removeServer(const char *srvName) { list::iterator iter=srvList.begin(); for(int i=0;igetName(),srvName)==0) { if(iter->isUp()) return false; iter->disconnectFromDBHost(); //it's not up, so it fails only if it is not connected at all srvList.erase(iter); return true; } iter++; } return false; } bool RasServerManager::testUniqueness(const char* srvName) { list::iterator iter=srvList.begin(); for(int i=0;igetName(),srvName)==0) return false; iter++; } return true; } RasServer& RasServerManager::operator[](int x) // FIXME: check against upper limit { list::iterator iter=srvList.begin(); for(int i=0;i::iterator iter=srvList.begin(); for(int i=0;igetName(),srvName)==0) return *iter; iter++; } return protElem; } RasServer& RasServerManager::last() { return srvList.back(); } int RasServerManager::countServers() { return srvList.size(); } // return values of changeServerStatus: #define SERVERSTATUS_OK 0 #define SERVERSTATUS_ERR -1 int RasServerManager::changeServerStatus(char *reqMessage) { char serverName[50]; int newstatus; long infCount; sscanf(reqMessage,"%s %d %ld",serverName,&newstatus,&infCount); TALK( "RasServerManager::changeServerStatus: Trying to change status of "<::iterator iter=srvList.begin(); for(int i=0;igetDBHostName(); if(cDbhName==NULL) continue; if(strcmp(cDbhName,dbhName)==0) iter->disconnectFromDBHost(); } } int RasServerManager::countUpServers() { int count=0; list::iterator iter=srvList.begin(); for(int i=0;iisUp()) count++; iter++; } TALK( "RasServerManager::countUpServers() -> " << count ); return count; } void RasServerManager::printStatus() { char buff[100]; list::iterator iter=srvList.begin(); TALK( "RasServerManager::printStatus. current status is:" ); for(int i=0;igetDescription(buff); TALK( "\t" << i << ": " << buff ); iter++; } } bool RasServerManager::reset() { // test modus only if(config.isTestModus()==false) return false; list::iterator iter=srvList.begin(); for(int i=0;iisUp()) return false; } iter=srvList.begin(); for(int i=0;idisconnectFromDBHost(); //it's not up, so it fails only if it is not connected at all } while(srvList.size()) { srvList.pop_front(); } return true; } bool RasServerManager::acceptChangeName(const char *oldName,const char *newName) { if(strcmp(oldName,newName)==0) return true; // if someone really wants to change a name with the same, return testUniqueness(newName); }