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

address.c

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

      address.c -- struct sockaddr bookkeeping
      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: address.c 23144 2007-12-21 15:36:48Z wsl $
      $URL: https://infix.uvt.nl/its-id/trunk/sources/fair-0.5.1/src/address.c $

******************************************************************************/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

#include "fair.h"
#include "error.h"
#include "worker.h"
#include "chrono.h"
#include "conf.h"

#include "address.h"

static unsigned int address_number = 0;

static address_t address_0 = {{0}};

bool address_string_sa(address_string_t *str, const struct sockaddr *sa, socklen_t len) {
      int err;

      unless(str) return FALSE;
      unless(sa) {
            strcpy(str->host, "(null)");
            strcpy(str->serv, "(null)");
            return FALSE;
      }

      err = getnameinfo(sa, len,
            str->host, sizeof str->host,
            str->serv, sizeof str->serv,
            NI_NUMERICHOST|NI_NUMERICSERV);

      if(err) {
            syslog(LOG_WARNING, "getnameinfo(NI_NUMERICHOST|NI_NUMERICSERV): %s.", gai_strerror(err));
            strcpy(str->host, "(err)");
            strcpy(str->serv, "(err)");
            return FALSE;
      }
      return TRUE;
}

bool address_string(address_string_t *str, const address_t *addr) {
      unless(addr) {
            strcpy(str->host, "(null)");
            strcpy(str->serv, "(null)");
            return FALSE;
      }
      return address_string_sa(str, address_sa(addr), addr->len);
}

int address_cmp_addr(const address_t *aa, const address_t *ba) {
      socklen_t al, bl;

      if(aa && !ba)
            return -1;
      if(!aa && ba)
            return 1;

      al = aa->len;
      bl = ba->len;
      if(al < bl)
            return -1;
      if(al > bl)
            return 1;
      return memcmp(aa + 1, ba + 1, al);
}

int address_cmp_prio(const address_t *aa, const address_t *ba) {
      bool ab, bb;
      u32 ar, br;
#if 0
      sa_family_t af, bf;
#endif

      if(aa && !ba)
            return -1;
      if(!aa && ba)
            return 1;

      ab = aa->disabled;
      bb = ba->disabled;
      if(!ab && bb)
            return -1;
      if(ab && !bb)
            return 1;

      ab = aa->dead;
      bb = ba->dead;
      if(!ab && bb)
            return -1;
      if(ab && !bb)
            return 1;

      ar = aa->nconn;
      br = ba->nconn;
      if(ar < br)
            return -1;
      if(ar > br)
            return 1;

      ar = aa->errors;
      br = ba->errors;
      if(ar < br)
            return -1;
      if(ar > br)
            return 1;

#if 0
      af = address_sa(aa)->sa_family;
      bf = address_sa(ba)->sa_family;
      if(af > bf)
            return -1;
      if(af < bf)
            return 1;

      if(aa < ba)
            return -1;
      if(aa > ba)
            return 1;
#endif

      return 0;
}

static void address_enable(chrono_t *cr) {
      address_t *addr;

      unless(cr) return;
      addr = cr->data;
      unless(addr) return;

      addr->disabled = FALSE;
      if(addr->func)
            addr->func(addr, ADDRESS_EVENT_STATECHANGE);
}

static void address_disable(address_t *addr) {
      unless(addr) return;
      addr->disabled = TRUE;
      if(addr->func)
            addr->func(addr, ADDRESS_EVENT_STATECHANGE);
      chrono_after(addr->whip, conf_BenchPeriod * addr->errors);
}

void address_working(address_t *addr) {
      u8 olderrors;
      unless(addr) return;
      olderrors = addr->errors;
      if(olderrors)
            addr->errors = olderrors - 1;
}

void address_broken(address_t *addr) {
      u8 errors, olderrors;
      unless(addr) return;
      if(!addr->disabled) {
            olderrors = addr->errors;
            errors = olderrors + 1;
            if(errors < olderrors)
                  errors = ~0;
            if(errors != olderrors)
                  addr->errors = errors;
            address_disable(addr);
      }
}

void address_update(address_t *addr) {
      unless(addr) return;

      chrono_after(addr->timer, conf_PingTimeout);
      if(addr->dead) {
            addr->dead = FALSE;
            syslog(LOG_WARNING, "worker node %s %s alive again",
                  addr->str.host, addr->str.serv);
            if(addr->func)
                  addr->func(addr, ADDRESS_EVENT_STATECHANGE);
      }
}

static void address_decay(chrono_t *cr) {
      address_t *addr;

      unless(cr) return;
      addr = cr->data;
      unless(addr) return;

      if(!addr->dead) {
            addr->dead = TRUE;
            syslog(LOG_WARNING, "worker node %s %s timed out",
                  addr->str.host, addr->str.serv);
            if(addr->func)
                  addr->func(addr, ADDRESS_EVENT_STATECHANGE);
      }
}

unsigned int address_count(void) {
      return address_number;
}

bool address_authorized(const struct sockaddr *sa, socklen_t len) {
      address_string_t str;
      unless(sa && len > 0) return FALSE;

      address_string_sa(&str, sa, len);
      if(regexec(conf_AllowUDP, str.host, 0, NULL, 0)) {
            syslog(LOG_WARNING, "Unauthorized address: %s %s",
                  str.host, str.serv);
            return FALSE;
      }
      return TRUE;
}

address_t *address_new(const struct sockaddr *sa, socklen_t len, address_hook_t func, void *data) {
      address_t *addr;
      unless(sa && len > 0) return NULL;

      addr = xalloc(sizeof *addr + len);
      *addr = address_0;
      addr->func = func;
      addr->data = data;

      memcpy(addr+1, sa, addr->len = len);

      avl_init_node(&addr->node, addr);
      avl_init_node(&addr->prio, addr);

      address_string_sa(&addr->str, sa, len);

      addr->timer = chrono_new(address_decay, addr);
      addr->whip = chrono_new(address_enable, addr);

      chrono_after(addr->timer, conf_PingTimeout);
      address_number++;

      return addr;
}

address_t *address_byaddr(avl_tree_t *t, const struct sockaddr *sa, socklen_t len) {
      avl_node_t *n;
      address_t *addr;
      unless(t) return NULL;
      unless(sa && len > 0) return NULL;
      addr = alloca(sizeof *addr + len);
      assert(addr);
      *addr = address_0;
      memcpy(addr+1, sa, addr->len = len);
      n = avl_search(t, addr);
      return n ? n->item : NULL;
}

void address_load(address_t *addr) {
      unless(addr) return;
      addr->nconn++;
      if(addr->func)
            addr->func(addr, ADDRESS_EVENT_LOAD);
}

void address_unload(address_t *addr) {
      unless(addr) return;
      addr->nconn--;
      if(addr->func)
            addr->func(addr, ADDRESS_EVENT_UNLOAD);
}

Generated by  Doxygen 1.6.0   Back to index