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

carrousel.c

/******************************************************************************

      carrousel.c -- main loadbalancer program
      Copyright (C) 2004  Wessel Dankers <wsl@uvt.nl>

      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, write to the Free Software
      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

      $Id: carrousel.c 23144 2007-12-21 15:36:48Z wsl $
      $URL: https://infix.uvt.nl/its-id/trunk/sources/fair-0.5.1/src/carrousel.c $

******************************************************************************/

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <pwd.h>
#include <grp.h>

#include "fair.h"
#include "protocol.h"
#include "error.h"
#include "relay.h"
#include "sock.h"
#include "conn.h"
#include "chrono.h"
#include "fdcopy.h"
#include "worker.h"
#include "address.h"
#include "init.h"
#include "conf.h"

static void incoming_tcp(void *_, int fd, const struct sockaddr *sa, socklen_t sa_len) {
      relay_new(fd, sa, sa_len);
}

static void klokje(chrono_t *cr) {
      struct tm *tm;
      time_t walltime = now / STAMP_TICKS;
      stamp_t next = (STAMP_TICKS/4) - now % (STAMP_TICKS/4);

      if(next < STAMP_TICKS/100)
            next += (STAMP_TICKS/4);

      if(cr)
            chrono_after(cr, next);

      tm = localtime(&walltime);
      eprintf("\r%04d-%02d-%02d %02d:%02d:%02d.%06d cr:%u rl:%u cn:%u fd:%u fdc:%u lst:%u wrk:%u addr:%u\033[K\r",
            tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
            tm->tm_hour, tm->tm_min, tm->tm_sec,
            (int)(now % STAMP_TICKS),
            chrono_count(), relay_count, connector_count(), fd_count(),
            fdcopy_count(), listener_count(), worker_count(), address_count());
}

static bool strsane(const char *s, size_t len) {
      const char *e;
      unless(s && len >= 0) return FALSE;
      for(e = s + len; s < e; s++)
            if(!isprint(*s))
                  return FALSE;
      return TRUE;
}

static void incoming_udp(fd_t *fd, fd_event_t evt) {
      struct sockaddr_storage _sa;
      struct sockaddr *sa = (struct sockaddr *)&_sa;
      socklen_t len = sizeof _sa;
      byte buf[1024];
      char *hostname;
      ssize_t r;
      loadping_t *p = (loadping_t *)buf;
      worker_t *w;
      int load;

      unless(fd) return;

      r = recvfrom(fd->fd, buf, sizeof buf - 1, 0, sa, &len);
      if(r < sizeof *p)
            return;
      if(p->version != PROTOCOL_VERSION)
            return;
      if(!p->hostlen)
            return;
      if(r != sizeof *p + p->hostlen)
            return;

      hostname = buf + sizeof *p;
      if(memchr(hostname, '\0', p->hostlen))
            return;
      hostname[p->hostlen] = '\0';
      load = ntohs(p->capacity);

      w = worker_byname(hostname);
      if(!w && strsane(hostname, p->hostlen) && address_authorized(sa, len))
            w = worker_new(hostname);
      if(w)
            worker_update(w, load, sa, len);
}

int main(int argc, char **argv) {
      const char *err;
      int opt;
      char *config = NULL;

      while((opt = getopt(argc, argv, "c:")) != EOF) {
            switch(opt) {
                  case 'c':
                        config = strdup(optarg);
                        break;
                  default:
                        syslog_exit(LOG_CRIT, "Unknown option. Program exit.");
                        break;
            }
      }

      openlog("carrousel", LOG_NDELAY|LOG_PID, LOG_DAEMON);

      if(!init_signals())
            syslog_exit(LOG_CRIT, "sigaction(): %m. Program exit.");

      stamp_sync();

      if(!conf_load(config, FALSE))
            syslog_exit(LOG_CRIT, "Error reading config file. Program exit.");

      init_limits();

      if(conf_Debug)
            chrono_after(chrono_new(klokje, NULL), 0LL);

      err = listener_new_tcp(conf_BalancerService, incoming_tcp, NULL);
      if(err)
            syslog_exit(LOG_CRIT, "Error listening on TCP port %s: %s", conf_BalancerService, err);

      err = listener_new_udp(conf_TransponderService, incoming_udp, NULL);
      if(err)
            syslog_exit(LOG_CRIT, "Error listening on UDP port %s: %s", conf_TransponderService, err);

      if(!conf_Debug && !init_daemon())
            syslog_exit(LOG_CRIT, "while backgrounding: %m. Exiting.");

      if(conf_DropPrivs && !init_privs())
            syslog_exit(LOG_CRIT, errno == ENOENT
                  ? "init_privs(): user/group ID not found"
                  : "init_privs(): %m");

      syslog(LOG_INFO, "carrousel started, listening on %s/tcp and %s/udp",
            conf_BalancerService, conf_TransponderService);

      for(;;) {
            fd_select(chrono_events());
            if(init_hupped) {
                  init_hupped = FALSE;
                  if(conf_reload(config))
                        syslog(LOG_INFO, "Config reloaded.");
                  else
                        syslog(LOG_ERR, "Errors in config file, not reloaded");
            }
      }

      return 0;
}

Generated by  Doxygen 1.6.0   Back to index