Logo Search packages:      
Sourcecode: netams version File versions  Download package

services.c

/*************************************************************************
***   Authentication, authorization, accounting + firewalling package
***   Copyright 1998-2002 Anton Vinokurov <anton@netams.com>
***   Copyright 2002-2008 NeTAMS Development Team
***   This code is GPL v3
***   For latest version and more info, visit this project web page
***   located at http://www.netams.com
***
*************************************************************************/
/* $Id: services.c,v 1.147 2009-08-01 09:23:55 anton Exp $ */

#include "netams.h"

//////////////////////////////////////////////////////////////////////////
ServicesList *Services=NULL;
//////////////////////////////////////////////////////////////////////////
const char *service_type_name[SERVICE_TYPES_NUM]= { "undef", "storage", "processor", "data-source", "monitor", "html", "quota", "quotactl", "login", "alerter", "scheduler", "billing", "weblogin", "empty", "server", "main", "ds_ipq", "ds_ipfw", "ds_libpcap", "ds_ulog", "ds_netgraph", "ds_netflow", "acl-server", "ds_raw" };

/////////////////////////////////////////////////////////////////////////
int cShowService        (struct cli_def *cli, const char *cmd, char **argv, int argc);
int cShowServicesList   (struct cli_def *cli, const char *cmd, char **argv, int argc);
int cService            (struct cli_def *cli, const char *cmd, char **argv, int argc);
int cServiceStart (struct cli_def *cli, const char *cmd, char **argv, int argc);
int cServiceStop  (struct cli_def *cli, const char *cmd, char **argv, int argc);
/////////////////////////////////////////////////////////////////////////
//defined commands
static const  struct CMD_DB cmd_db[] = {
{ 2, 0, 0, "show",      PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL,            "shows various system parameters" },
{ 0, 2, 0, "service",   PRIVILEGE_UNPRIVILEGED, MODE_EXEC, cShowService,      "service data" },
{ 3, 2, 0, "services",  PRIVILEGE_UNPRIVILEGED, MODE_EXEC, cShowServicesList, "available services" },

{ 8, 0, 1, "service",   PRIVILEGE_UNPRIVILEGED, MODE_CONFIG, NULL,            "set up service" },
{ 0, 8, 8, "acl-server", PRIVILEGE_UNPRIVILEGED, MODE_CONFIG, cService,       NULL },
{ 0, 8, 8, "alerter",   PRIVILEGE_UNPRIVILEGED, MODE_CONFIG, cService,        NULL },
{ 0, 8, 8, "billing",   PRIVILEGE_UNPRIVILEGED, MODE_CONFIG, cService,        NULL },
{ 0, 8, 8, "data-source", PRIVILEGE_UNPRIVILEGED, MODE_CONFIG, cService,      NULL },
{ 0, 8, 8, "html",      PRIVILEGE_UNPRIVILEGED, MODE_CONFIG, cService,        NULL },
{ 0, 8, 8, "login",     PRIVILEGE_UNPRIVILEGED, MODE_CONFIG, cService,        NULL },
{ 0, 8, 8, "monitor",   PRIVILEGE_UNPRIVILEGED, MODE_CONFIG, cService,        NULL },
{ 0, 8, 8, "processor", PRIVILEGE_UNPRIVILEGED, MODE_CONFIG, cService,        NULL },
{ 0, 8, 8, "quota",     PRIVILEGE_UNPRIVILEGED, MODE_CONFIG, cService,        NULL },
{ 0, 8, 8, "quotactl",  PRIVILEGE_UNPRIVILEGED, MODE_CONFIG, cService,        NULL },
{ 0, 8, 8, "scheduler", PRIVILEGE_UNPRIVILEGED, MODE_CONFIG, cService,        NULL },
{ 0, 8, 8, "server",    PRIVILEGE_UNPRIVILEGED, MODE_CONFIG, cService,        NULL },
{ 0, 8, 8, "storage",   PRIVILEGE_UNPRIVILEGED, MODE_CONFIG, cService,        NULL },
{ -1, 0, 0, NULL,  0, 0, NULL, NULL }
};
//////////////////////////////////////////////////////////////////////////
Service::Service(service_type s_type, u_char i):Object(){
      serv_type=s_type;
      instance=i;

      id=((unsigned)s_type)*1000+instance;      //make uniq id

      t_id=(pthread_t)0;

      netams_mutex_init(&sleep_mutex, NULL);
      pthread_cond_init(&sleep_cond, NULL);

      sleep_state=0;
      serv_flags=SERVICE_FLAG_NONE;
}

Service::~Service(){
      aLog(D_INFO, "destroying service %s:%u\n", getName(), instance);
      netams_mutex_destroy(&sleep_mutex);
      pthread_cond_destroy(&sleep_cond);
}

const char *Service::getName(){
      return service_type_name[serv_type];
}
//////////////////////////////////////////////////////////////////////////
//common calls
int cServiceProcessCfg  (struct cli_def *cli, const char *cmd, char **argv, int argc) {
      Service *s;
      u_char no_flag;

      no_flag = CLI_CHECK_NO(argv[0]);
      if(no_flag) {
            argv=&argv[1];
            argc--;
      }

      s=(Service *)cli->service;
      return s->ProcessCfg(cli,argv,argc, no_flag);
}

void* ServiceWorker(void *ss) {
      Service *s = (Service*)ss;
      SET_CANCEL();

      pthread_cleanup_push(ServiceCancel, ss);

      s->Worker();
      s->serv_flags|=SERVICE_FLAG_FAULTY;
      s->serv_flags|=SERVICE_FLAG_DOWN;
      aLog(D_INFO, "service %s:%u thread start failed\n", s->getName(), s->instance);
      pthread_cleanup_pop(1);
      return NULL;
}
void  ServiceCancel(void *ss) {
      Service *s = (Service*)ss;

      s->Cancel();
      aLog(D_INFO, "service %s:%u thread cancelled\n", s->getName(), s->instance);
}

int cServiceStart(struct cli_def *cli, const char *cmd, char **argv, int argc) {
      Service *s = (Service*)cli->service;

      if(!(s->serv_flags&SERVICE_FLAG_DOWN)) {
            cli_error(cli, "Service %s:%u already running", s->getName(), s->instance);
            return CLI_OK;
      }

      s->serv_flags&=~SERVICE_FLAG_DOWN;
      cli_error(cli, "Starting service %s:%u", s->getName(), s->instance);
      s->Start();
      return CLI_OK;
}

void Service::Start() {
      if(serv_flags&SERVICE_FLAG_DOWN) return;

      aLog(D_INFO, "starting service %s:%u\n", getName(), instance);
      serv_flags&=~SERVICE_FLAG_FAULTY;
      if(serv_type!=SERVICE_MONITOR && serv_type!=SERVICE_MAIN) {
            pthread_create(&t_id, NULL, &ServiceWorker, (void*)this);
            aLog(D_INFO, "service %s:%u thread started\n", getName(), instance);
      }
}

int cServiceStop(struct cli_def *cli, const char *cmd, char **argv, int argc) {
      Service *s = (Service*)cli->service;

      if(s->serv_flags&SERVICE_FLAG_DOWN) {
            cli_error(cli, "Service %s:%u already down", s->getName(), s->instance);
            return CLI_OK;
      }
      cli_error(cli, "Shutting down service %s:%u", s->getName(), s->instance);
      s->Stop();
      return CLI_OK;
}

void Service::Stop(){
      if(serv_flags&SERVICE_FLAG_DOWN) return;
      serv_flags|=SERVICE_FLAG_DOWN;

      aLog(D_INFO, "Shutting down service %s:%u\n", getName(), instance);
      if(serv_type==SERVICE_MONITOR)
            Cancel();
      else if (serv_type!=SERVICE_MAIN && t_id) {
            Wakeup();
            pthread_cancel(t_id);
            Wakeup();
            pthread_join(t_id, NULL);  //it's necessary here because there is delete after it
      }
}

u_char Service::Sleep(unsigned sec){       // parameter in seconds!!!!
      int i;

      aDebug(DEBUG_SLEEP, "going to sleep service %s for %d secs\n", this->getName(), sec);

      TEST_CANCEL(;);
      netams_mutex_lock(&sleep_mutex);
      sleep_state=1;

      if (sec) {
            struct timespec ts;
            struct timeval tv;
            gettimeofday(&tv, NULL);

            TIMEVAL_TO_TIMESPEC(&tv, &ts);
            ts.tv_sec+=sec;

            i=pthread_cond_timedwait(&sleep_cond, &sleep_mutex, &ts);
      }
      else {
            i=pthread_cond_wait(&sleep_cond, &sleep_mutex);
      }

      sleep_state=0;
      netams_mutex_unlock(&sleep_mutex);
      TEST_CANCEL(;);

      if (i && i!=ETIMEDOUT) aLog(D_ERR, "sleeping of %s failed: %s\n", this->getName(), strerror(i));
      else if (i && i==ETIMEDOUT) return 1;

      return 0;
}

u_char Service::Wakeup(){
#ifdef DEBUG
      Service *s=Services->getServiceByThr(pthread_self());
      if(s)
            aDebug(DEBUG_SLEEP, "(%s:%u) waking up service %s:%u, %s\n",
                  s->getName(),s->instance, this->getName(), this->instance, !sleep_state?"WAS_UP":"WAS_DOWN");
      else
            aDebug(DEBUG_SLEEP, "(thread %u) waking up service %s:%u, %s\n",
                  pthread_self(), this->getName(), this->instance, !sleep_state?"WAS_UP":"WAS_DOWN");
#endif
      if (sleep_state==0) return 1;
      pthread_cond_signal(&sleep_cond);
      return 0;
}
//////////////////////////////////////////////////////////////////////////
ServicesList::ServicesList() : List() {
      InitCliCommands(cmd_db);
}

Service *ServicesList::getService(service_type type, u_char i){
      Service *s;

      netams_rwlock_rdlock(&rwlock);
      for(s=(Service*)root; s!=NULL; s=(Service*)s->next)
            if (s->serv_type==type && s->instance==i) break;
      netams_rwlock_unlock(&rwlock);
      return s;
}

Service *ServicesList::getServiceNextByType(service_type type, Service *s) {
      Service *d;

      netams_rwlock_rdlock(&rwlock);
      for(s?d=(Service*)s->next:d=(Service*)root; d!=NULL; d=(Service*)d->next)
            if(d->serv_type==type) break;
      netams_rwlock_unlock(&rwlock);
        return d;
}

Service *ServicesList::getServiceByThr(pthread_t t){
      Service *s;

      pthread_rwlock_rdlock(&rwlock);
      for(s=(Service*)root; s!=NULL; s=(Service*)s->next)
            if (pthread_equal(t, s->t_id)) break;
      pthread_rwlock_unlock(&rwlock);
      return s;
}

void ServicesList::StartAll(){
      Service *s;

//    netams_rwlock_rdlock(&rwlock);
        for (s=(Service*)root; s!=NULL; s=(Service*)s->next) {
            s->Start();
      }
//    netams_rwlock_unlock(&rwlock);
}

void ServicesList::ShutdownAll(){
      Service *s=NULL;

      //shutdown server first
      if((s=getServiceNextByType(SERVICE_SERVER))) s->Stop();

      //shutdown data-source, flush data to processor
      s=NULL;
      while((s=getServiceNextByType(SERVICE_DATASOURCE, s))) s->Stop();

      //shutdown processor and flush data to storages
      if((s=Processor)) s->Stop();

#ifdef HAVE_BILLING
      //shutdown billing and flush data to storages
      if((s=Billing)) s->Stop();
#endif

      //shutdown quota and flush data to storages
    if((s=Quota)) s->Stop();

      //shutdown login and flush data to storages
    if((s=Login)) s->Stop();

      s=NULL;
      while((s=getServiceNextByType(SERVICE_MONITOR, s))) {
            s->Stop();
      }

      //shutdown storages and flush data to disk
      s=NULL;
      while((s=getServiceNextByType(SERVICE_STORAGE, s))) s->Stop();

      for(Service *s=(Service*)root; s!=NULL;s=(Service*)s->next) {
            if (s!=sMain) {
                  s->Stop();
            }
      }
}

void ServicesList::ShowCfg(struct cli_def *cli, u_char flags) {
      Service *d;

      netams_rwlock_rdlock(&rwlock);
      for (d=(Service*)root; d!=NULL; d=(Service*)d->next) {
            if(!(d->serv_flags&SERVICE_FLAG_VISIBLE)) continue;
            if(!(flags&CFG_SHOW_SERVICE_LIST))
                  cli_bufprint(cli, "service");
            if(d->serv_flags&SERVICE_FLAG_SINGLE)
                  cli_bufprint(cli, " %s", d->getName());
            else
                  cli_bufprint(cli, " %s %u", d->getName(), d->instance);
            if(d->serv_flags&SERVICE_FLAG_FAULTY) cli_bufprint(cli, " (faulty)");
            if(d->serv_flags&SERVICE_FLAG_DOWN)    cli_bufprint(cli, " (stopped)");
            cli_bufprint(cli, "\n");
            if(!(flags&CFG_SHOW_SERVICE_LIST)) {
                  d->ShowCfg(cli, flags);
                  if(d->serv_flags&SERVICE_FLAG_DOWN) cli_print(cli, "stop");
                  cli_bufprint(cli, "\n");
            }
      }
      netams_rwlock_unlock(&rwlock);
}

void ServicesList::ShowInfo(struct cli_def *cli) {
      Service *d;

      netams_rwlock_rdlock(&rwlock);
      for (d=(Service*)root; d!=NULL; d=(Service*)d->next)
            d->ShowInfo(cli);
      netams_rwlock_unlock(&rwlock);
}

void ServicesList::ShowPerf(struct cli_def *cli, u_char isheader) {
      Service *d;

      netams_rwlock_rdlock(&rwlock);
      for (d=(Service*)root; d!=NULL; d=(Service*)d->next)
            d->ShowPerf(cli, isheader);
      netams_rwlock_unlock(&rwlock);
}
//////////////////////////////////////////////////////////////////////////
int cService(struct cli_def *cli, const char *cmd, char **argv, int argc){
      Service *s;
      u_char instance=0;
      service_type type=SERVICE_UNDEF;
      const char *name=NULL;
    u_char no_flag=0;
      no_flag = CLI_CHECK_NO(argv[0]);
      if(no_flag) {
            argv=&argv[1];
            argc--;
      }

      //GET SERVICE PARAMS
      name=argv[1];

      for(u_char i=1;i<SERVICE_TYPES_NUM;i++) {
            if(STREQ(name, service_type_name[i])) {
                  type=(service_type)i;
                  name=service_type_name[i];
                  break;
            }
      }

      instance = (argc>2)?strtol(argv[2], NULL, 10):0;

      u_char i=2;
      if(argv[i] && isdigit(argv[i][0])) {
            instance = strtol(argv[i], NULL, 10);
            i++;
      }

      //check for services that might be only in single instance
      if(type==SERVICE_PROCESSOR || type==SERVICE_SCHEDULER || type==SERVICE_QUOTA \
      || type==SERVICE_LOGIN || type==SERVICE_BILLING \
      || type==SERVICE_HTML || type==SERVICE_ACL_SERVER) {
            if(instance) cli_error(cli, "Service might be only in one instance. Using %s:0 instead",name);
            instance=0;
      }

      s=Services->getService(type, instance);
      if (s) {
            if (is_running) gettimeofday(&when_config_changed, NULL);

            if(no_flag) {
                  cli_error(cli, "uninitialing service %s:%u", name, instance);
                  s->Stop();
                  Services->Delete(s);
                  delete s;
                  return CLI_OK;
            } else {
                  if(STREQ(argv[i], "start")) {
                        if(!(s->serv_flags&SERVICE_FLAG_DOWN)) {
                              cli_error(cli, "Service %s:%u already running", s->getName(), s->instance);
                              return CLI_OK;
                        }
                        cli_error(cli, "Starting service %s:%u", name, instance);
                        s->Start();
                  } else if(STREQ(argv[i], "stop")) {
                        if(s->serv_flags&SERVICE_FLAG_DOWN) {
                              cli_error(cli, "Service %s:%u already down", s->getName(), s->instance);
                              return CLI_OK;
                        }
                        cli_error(cli, "Stoping service %s:%u", name, instance);
                        s->Stop();
                  }

                  cli->service=s;
                  cli_error(cli, "switching to service %s:%u for configuring", name, instance);
                  char buf[32];
                  sprintf(buf, "%s:%u", s->getName(), s->instance);
                  cli_set_configmode(cli, s->cli_mode, buf);
            }
      } else {
            if(no_flag) {
                  cli_error(cli, "service %s not exist", name);
                  return CLI_OK;
            }
            u_char mode;
            cli_error(cli, "creating service %s:%u", name, instance);
            aLog(D_INFO, "initializing service %s:%u\n", name, instance);

            switch(type) {
                  case SERVICE_STORAGE:
                        mode=MODE_STORAGE;
                        s=InitStorageService();
                        break;
                  case SERVICE_PROCESSOR:
                        mode=MODE_PROCESSOR;
                        s=(Service*)new Service_Processor();
                        s->serv_flags|=SERVICE_FLAG_SINGLE;
                        break;
                  case SERVICE_DATASOURCE:
                        mode=MODE_DATASOURCE;
                        s=InitDatasourceService();
                        break;
                  case SERVICE_MONITOR:
                        mode=MODE_MONITOR;
                        s=InitMonitorService();
                        break;
                  case SERVICE_HTML:
                        mode=MODE_HTML;
                        s=(Service*)new Service_Html();
                        s->serv_flags|=SERVICE_FLAG_SINGLE;
                        break;
                  case SERVICE_QUOTA:
                        mode=MODE_QUOTA;
                        s=InitQuotaService();
                        break;
                  case SERVICE_QUOTACTL:
                        mode=MODE_QUOTACTL;
                        s=InitQuotactlService();
                        break;
                  case SERVICE_LOGIN:
                        mode=MODE_LOGIN;
                        s=InitLoginService();
                        break;
                  case SERVICE_ALERTER:
                        mode=MODE_ALERTER;
                        s=InitAlerterService();
                        break;
                  case SERVICE_SCHEDULER:
                        mode=MODE_SCHEDULER;
                        s=InitSchedulerService();
                        break;
#ifdef HAVE_BILLING
                  case SERVICE_BILLING:
                        mode=MODE_BILLING;
                        s=InitBillingService();
                        break;
#endif
                  case SERVICE_SERVER:
                        mode=MODE_SERVER;
                        s=InitServerService();
                        break;
                  case SERVICE_ACL_SERVER:
                        mode=MODE_ACL_SERVER;
                        s=InitAclServerService();
                        break;
                  default:
                        return CLI_OK;
            }
            s->serv_flags|=SERVICE_FLAG_VISIBLE;
            s->instance = instance;
            s->cli_mode = mode;
            s->id = Services->num_objects;      //workaround for List hash
            Services->Insert(s);
            cli->service=s;

            char buf[32];
            sprintf(buf, "%s:%u", s->getName(), s->instance);
            cli_set_configmode(cli, mode, buf);
      }
      return CLI_OK;
}
/////////////////////////////////////////////////////////////////////////
Service* aStorageGetAccepted(st_conn_type conn_type){
      Service *st=NULL;

      while((st = Services->getServiceNextByType(SERVICE_STORAGE, st))) {
            if (((Service_Storage_Interface*)st)->isAccepted(conn_type))
                  return st;
      }
      return NULL;
}
//////////////////////////////////////////////////////////////////////////
Service** aStorageGetAcceptedAll(st_conn_type conn_type, Service ***ptr){
      Service **list;
      Service *st=NULL;
      if(!ptr)
            ELIST_INIT(list);
      else
            list = *ptr;

      while((st = Services->getServiceNextByType(SERVICE_STORAGE, st))) {
            if(((Service_Storage_Interface*)st)->isAccepted(conn_type))
                  ELIST_ADD(list, st);
      }
      return list;
}
/////////////////////////////////////////////////////////////////////////
int cShowService (struct cli_def *cli, const char *cmd, char **argv, int argc) {
      u_char instance=0;
      service_type type=SERVICE_UNDEF;
      const char *name=NULL;

      //GET SERVICE PARAMS
      name=argv[2];

      for(u_char i=1;i<SERVICE_TYPES_NUM;i++) {
            if(STREQ(name, service_type_name[i])) {
                  type=(service_type)i;
                  name=service_type_name[i];
                  break;
            }
      }

      instance = (argc>3)?strtol(argv[3], NULL, 10):0;

      u_char i=3;
      if(argv[i] && isdigit(argv[i][0])) {
            instance = strtol(argv[i], NULL, 10);
            i++;
      }

      Service *d = Services->getService(type, instance);
      if(d != NULL ) {
            if(d->serv_flags&SERVICE_FLAG_SINGLE)
                  cli_bufprint(cli, "service %s", d->getName());
            else
                  cli_bufprint(cli, "service %s %u", d->getName(), d->instance);

            cli_bufprint(cli, "%s\n", (d->serv_flags&SERVICE_FLAG_FAULTY)?" (faulty)":"");
            d->ShowCfg(cli, 0);
            if(d->serv_flags&SERVICE_FLAG_DOWN) cli_print(cli, "stop");
            cli_bufprint(cli, "\n");
      }
      return CLI_OK;
}

int cShowServicesList   (struct cli_def *cli, const char *cmd, char **argv, int argc) {
      Services->ShowCfg(cli, CFG_SHOW_SERVICE_LIST);
      return CLI_OK;
}

/////////////////////////////////////////////////////////////////////////

Generated by  Doxygen 1.6.0   Back to index