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

s_server.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: s_server.c,v 1.69 2009-08-01 09:23:55 anton Exp $ */

#include "netams.h"

static int initialized=0;
//////////////////////////////////////////////////////////////////////////
int cShowConnections    (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, "connections",     PRIVILEGE_UNPRIVILEGED, MODE_EXEC, cShowConnections,  "active connections to server" }, 
{ 0, 0, 0, "listen",    PRIVILEGE_UNPRIVILEGED, MODE_SERVER, cServiceProcessCfg,    NULL },
{ 26, 0, 0, "login",    PRIVILEGE_UNPRIVILEGED, MODE_SERVER, NULL,                  NULL },
{ 0, 26, 0, "any",      PRIVILEGE_UNPRIVILEGED, MODE_SERVER, cServiceProcessCfg,    NULL },
{ 0, 26, 0, "local",    PRIVILEGE_UNPRIVILEGED, MODE_SERVER, cServiceProcessCfg,    NULL },
{ 0, 0, 0, "max-conn",  PRIVILEGE_UNPRIVILEGED, MODE_SERVER, cServiceProcessCfg,    NULL },
{ 0, 0, 0, "start",     PRIVILEGE_UNPRIVILEGED, MODE_SERVER, cServiceStart,             NULL },
{ 0, 0, 0, "stop",      PRIVILEGE_UNPRIVILEGED, MODE_SERVER, cServiceStop,  NULL },
{ -1, 0, 0, NULL,  0, 0, NULL, NULL }
};   
//////////////////////////////////////////////////////////////////////////
void *sServerConnection(void *c);
void sServerConnectionCancel(void *c_t);
//////////////////////////////////////////////////////////////////////////
class Service_Server: public Service {
      public:
            unsigned short port;
            u_char onlylocalhost;
            u_short max_conn;
            unsigned num_connections;
            int server_socket;

            Service_Server();
            ~Service_Server();

            void ShowCfg(struct cli_def *cli, u_char flags);
            int ProcessCfg(struct cli_def *cli, char **argv, int argc, u_char no_flag);
            void Worker();
            void Cancel();
};

Service* InitServerService() {
      if(!initialized) {
            InitCliCommands(cmd_db);
            initialized = 1;
      }
      return (Service*)new Service_Server();
}

Service_Server::~Service_Server() {
}
//////////////////////////////////////////////////////////////////////////
Service_Server::Service_Server():Service(SERVICE_SERVER) {
      port=20000;
      onlylocalhost=1;
      max_conn=6;
      num_connections=0;
      server_socket=0;
}
//////////////////////////////////////////////////////////////////////////
int Service_Server::ProcessCfg(struct cli_def *cli, char **param, int argc, u_char no_flag){
      if (STRARG(param[0], "listen")) {
            unsigned short port_t=strtol(param[1], NULL, 10);
            if (port_t>0 && port_t <65535) { 
                  port=port_t;
                  aLog(D_INFO, "server listen port set to %u\n", port);
                  cli_error(cli, "listen port set to %u", port);
            }
            else
                  cli_error(cli, "listen port must be between 1 and 65535");
      }
      else if (STREQ(param[0], "login")) {
            if (STREQ(param[1], "any")) {
                  aLog(D_INFO, "server login permitted from any host\n");
                  cli_error(cli, "login permitted from any host");
                  onlylocalhost=0;
            }
            else if (STRNEQ(param[1], "local", 5)) {
                  aLog(D_INFO, "server login permitted from localhost only\n");
                  cli_error(cli, "login permitted from localhost only");
                  onlylocalhost=1;
            }
      }
      else if (STRARG(param[0], "max-conn")) {
            unsigned short maxconn_t=strtol(param[1], NULL, 10);
            if (maxconn_t>0 && maxconn_t <256) { 
                  max_conn=maxconn_t;
                  aLog(D_INFO, "server maximum connections number is set to %u\n", maxconn_t);
                  cli_error(cli, "maximum connections number is set to %u", maxconn_t);
            }
            else
                  cli_error(cli, "maximum connections number must be between 1 and 255");
      }
      return CLI_OK;
}
//////////////////////////////////////////////////////////////////////////
void Service_Server::Worker(){
      int server_socket, connection_socket;
      int status, addrlen, reuseaddr_on=1;
      struct sockaddr_in server_addr;
      struct sockaddr_in connection_addr;

      pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
      pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);

      if ((server_socket=socket(AF_INET,SOCK_STREAM,0))==-1 ) 
            aLog(D_CRIT, "creation of server socket() failed: %d (%s)\n", server_socket, strerror(errno));

      bzero(&server_addr, sizeof(server_addr));
      server_addr.sin_family=AF_INET;
      server_addr.sin_addr.s_addr=htonl(onlylocalhost?INADDR_LOOPBACK:INADDR_ANY);
      server_addr.sin_port=htons((unsigned short)(port));
      // set option for reuse address
      setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, (void*)&reuseaddr_on, sizeof(reuseaddr_on));
 
      // bind socket with serv_addr 
      status=bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr));
      if(status==-1 ) {
            aLog(D_CRIT, "bind of server socket failed: %u (%s) [%x]\n[maybe NeTAMS is already running? issue 'ps -ax | grep netams']\n", errno, strerror(errno), server_addr.sin_addr.s_addr);
            return;
      }
      status=listen(server_socket, SOMAXCONN);
      if(status==-1) {
            aLog(D_CRIT, "listen of server socket failed: %d (%s)\n", status, strerror(errno)); 
            return;
      }
      SET_POLL(server_socket);
      aLog(D_INFO, "server is listening\n");
      
      addrlen=sizeof(connection_addr);
      
      while(1) {
            CHECK_POLL(this, status);
            if( !status ) continue;
            
            connection_socket=accept(server_socket,(struct sockaddr*)(&connection_addr),(socklen_t*)(&addrlen));
            if (connection_socket==-1) {
                  if(errno!=EINTR)
                        aLog(D_CRIT, "accept of connection failed: %d (%s)\n", connection_socket, strerror(errno));
                  continue;
            }
            if (num_connections==max_conn) {
                  aLog(D_WARN, "no more room for aditional connection\n");
                  close(connection_socket); 
                  continue; 
            }

            Connection *conn = new Connection();
            conn->setConnection(connection_socket, &connection_addr);
            conn->id=++Connections->last_conn_id;
            Connections->Insert(conn);

            status = pthread_create(&(conn->t_id), NULL, &sServerConnection, conn);
            if (status != 0) 
                  aLog(D_ERR, "Creation of connection %d listener thread failed: %d\n", connection_socket, status); 
      }
}
//////////////////////////////////////////////////////////////////////////
void Service_Server::Cancel(){
      aLog(D_INFO, "cancelling connections\n");

      Connections->CancellAll();
      shutdown(server_socket, SHUT_RDWR);
      close(server_socket);
}
//////////////////////////////////////////////////////////////////////////
void *sServerConnection(void *c_t){
      Connection *c     = (Connection*)c_t;
      char buf[32];
      aDebug(DEBUG_SERVER, "connection %u from %s\n", c->id, inet_ntop(AF_INET, &(c->addr->sin_addr), buf, 32));
      pthread_cleanup_push(sServerConnectionCancel, c);
      pthread_detach(pthread_self());
      c->t_id=pthread_self();

      // Set the hostname (shown in the the prompt)
      //cli_set_hostname(c->cli, ">");

      // Set the greeting
      cli_set_banner(c->cli, SHOW_VERSION);

      cli_loop(c->cli, c->socket);

      pthread_cleanup_pop(1);
      return NULL;
}
//////////////////////////////////////////////////////////////////////////
void sServerConnectionCancel(void *c_t){
      Connection *c = (Connection*)c_t;
      aDebug(DEBUG_SERVER, "cancelling connection %u\n", c->id);
      Connections->Delete(c);
      c->clearConnection();
      delete c;
}
//////////////////////////////////////////////////////////////////////////
void Service_Server::ShowCfg(struct cli_def *cli, u_char flags){
      cli_print(cli, "login %s", onlylocalhost?"local":"any");
      cli_print(cli, "listen %u", port);
      cli_print(cli, "max-conn %u", max_conn);
}
//////////////////////////////////////////////////////////////////////////
int cShowConnections(struct cli_def *cli, const char *cmd, char **argv, int argc){
      Connections->listConnections(cli);
      return CLI_OK;
}
//////////////////////////////////////////////////////////////////////////

Generated by  Doxygen 1.6.0   Back to index