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

wackamole.c

/*
 * The Wackamole Program.
 *     
 * The contents of this file are subject to the CNDS Open Source
 * License, Version 1.0 (the ``License''); you may not use
 * this file except in compliance with the License.  You may obtain a
 * copy of the License at:
 *
 * http://www.backhand.org/wackamole/license/
 *
 * or in the file ``license.txt'' found in this distribution.
 *
 * Software distributed under the License is distributed on an AS IS basis, 
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
 * for the specific language governing rights and limitations under the 
 * License.
 *
 * The Creators of Wackamole are:
 *  Yair Amir, Ryan Caudy, Aashima Munjal and Theo Schlossnagle.
 *
 *  Copyright (C) 2000-2001 The Johns Hopkins University
 *  All Rights Reserved.
 *
 *  This product uses the Spread toolkit, developed by Spread Concepts LLC.
 *  For more information about Spread see http://www.spread.org
 *
 *  Wackamole development was partially funded by a grant from the Defense
 *  Advanced Research Projects Agency (DARPA) to Johns Hopkins University. The 
 *  U.S. Government retains certain rights in this software.
 *
 */



#include "config.h"
#include "wackamole.h"
#include "version.h"
#include "configuration.h"
#include "alarm.h"
#include "ife.h"
#include "arpcache.h"
#include "spoofmanager.h"
#include "control.h"

/* message types */
#define           STATE_MESS  1
#define           MATURING_MESS     2
#define           BALANCE_MESS      3
#define           OPERATOR_MESS     4
#define           ARPCACHE_MESS     5

/* automaton states */
#define           BOOT        1
#define           RUN         2
#define           GATHER            3
#define           BALANCE           4

/* claim priority */
#define           UNCLAIMED   0
#define           CLAIMED_BOOT      1     /* pseudo ip is taken by machine but not by booting wackamole */
#define           CLAIMED           2     /* pseudo ip is managed by this wackamole */
#define           PREFER_BOOT 3     /* wackamole is the preferred one and it is taken by machine at boot */
#define           PREFER            4     /* wackamole is the preferred one to manage this pseudo ip */
#define           PREFER_CLAIMED  5 /* wackamole is the preferred one and is actively managing it */

/* ALARM Extension */
#define LOGIC 0x00000008

/* state structures */
static  int       global_exit = 0;
static      int         State;
static  int32           Old_maturity;
static  int32           Maturity;
      int         spread_lock;

/* static  struct interface iface, idown; */
struct  in_addr         vip_in_addr;
/* static  char            ifname[IFNAMSIZ]; */
/* static  char            my_host_name[55]; */
/* static  int             my_host_name_len; */
static      int         Num_members;
static      member            Members[MAX_PSEUDO];

static  member          My;
static      int         My_index; /* in Members */

static      group_id    Gid;

static  pid_t           pid;

/* Spread structures */
      mailbox           Mbox = -1;
static      char        User[80];
static      char        Private_group[MAX_GROUP_NAME];

static      char        Mess[MAX_MESS_LEN];
static      int16       Mess_type;
static      int         Endian_mismatch;
static      int         Service_type, Num_groups;
static      int         Num_pending_states;
static      char        Target_groups[MAX_PSEUDO][MAX_GROUP_NAME];
static      char        Sender[MAX_GROUP_NAME];
static  char            File_name[100];
static  int       Debug = 0;

static      void  Usage( int argc, char *argv[] );
static      void  Handle_network();

static      void  Handle_membership();
static      void  Handle_state();
static      void  Handle_mature();
static      void  Handle_balance();
static      void  Handle_operator();
static      void  Handle_arp_cache(int *, int);

static      void  Send_state_message();
static  void      Send_local_arp_cache_repeat();
static  void      Send_local_arp_cache();
static      void  Turn_mature();

static      void  Wackamole_init();
static      void  Bye();

static  void    Priority_claim();
static  void    Claim_unclaimed();
static  entry  *findVEFromAddress( address Addr );
/* static  void    AcquireAddress( address Addr ); */
static  void    Acquire( entry *VE );
static  void    ReleaseAddress( address Addr );
static  void    Release( entry *VE );
static  void    Balance();
static  void    Print_alloc();
/* static  void    String_addr( address Addr, char IP[16] ); */
static  void    Sig_handler(int signum);
      void    Clean_up();
      void    Spread_reconnect(int ret);

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

int main( int argc, char *argv[] )
{
  int       fd;
  struct sigaction signalaction;
 
  E_init();
  Alarm_set( PRINT | EXIT ); 
 
  Usage( argc, argv );
  Wackamole_init();

  Alarm( PRINT, "\n/==============================================================================\\");
  Alarm( PRINT, "| The Wackamole Program.                                                       |");
  Alarm( PRINT, "| Copyright (c) 2000-2001 The Johns Hopkins University                         |"); 
  Alarm( PRINT, "| All rights reserved.                                                         |");
  Alarm( PRINT, "|                                                                              |");
  Alarm( PRINT, "| Wackamole is developed at the Center for Networking and Distributed Systems, |");
  Alarm( PRINT, "| The Johns Hopkins University.                                                |");
  Alarm( PRINT, "|                                                                              |");
  Alarm( PRINT, "| The Wackamole package is licensed under the CNDS Open Source License         |");
  Alarm( PRINT, "| You may only use this software in compliance with the License.               |");
  Alarm( PRINT, "| A copy of the license can be found at                                        |");
  Alarm( PRINT, "| http://www.backhand.org/wackamole/license                                    |");
  Alarm( PRINT, "|                                                                              |");
  Alarm( PRINT, "| This product uses the Spread toolkit, developed by Spread Concepts LLC.      |");
  Alarm( PRINT, "| For more information about Spread see http://www.spread.org                  |");
  Alarm( PRINT, "|                                                                              |");
  Alarm( PRINT, "| This software is distributed on an \"AS IS\" basis, WITHOUT WARRANTY OF        |");
  Alarm( PRINT, "| ANY KIND, either express or implied.                                         |");
  Alarm( PRINT, "|                                                                              |");
  Alarm( PRINT, "| Creators:                                                                    |");
  Alarm( PRINT, "|    Yair Amir             yairamir@cnds.jhu.edu                               |");
  Alarm( PRINT, "|    Ryan Caudy            wyvern@cnds.jhu.edu                                 |");
  Alarm( PRINT, "|    Aashima Munjal        munjal@jhu.edu                                      |");
  Alarm( PRINT, "|    Theo Schlossnagle     jesus@cnds.jhu.edu                                  |");
  Alarm( PRINT, "|                                                                              |");
  Alarm( PRINT, "| For a full list of contributors, see Readme.txt in the distribution.         |");
  Alarm( PRINT, "|                                                                              |");
  Alarm( PRINT, "| WWW:     www.backhand.org     www.cnds.jhu.edu                               |");
  Alarm( PRINT, "| Contact: wackamole@backhand.org                                              |");
  Alarm( PRINT, "|                                                                              |");
  Alarm( PRINT, "| Version %-7s Released %-20s                                |", VERSION_STRING, VERSION_RELEASE_DATE); 
  Alarm( PRINT, "|                                                                              |");
  Alarm( PRINT, "\\==============================================================================|");

  if(Debug) 
    Alarm_set( PRINT | ARPING | DEBUG | EXIT );
  else {

    char pidstring[10];

    Alarm_enable_syslog("wackamole");
    Alarm_set(PRINT | EXIT);

    if(fork()) exit(1);
    setsid();
    if(fork()) exit(1);
    if( chdir("/") != 0 ){
      Alarm(PRINT,"chdir to root failed");
    }

    umask(0027);

    pid = getpid();
    fd = open(_PATH_WACKAMOLE_PIDDIR "/wackamole.pid",
            O_WRONLY|O_CREAT|O_TRUNC, 0644);
    if(fd < 0) {
      Alarm(EXIT,
          "Cannot write PID file " _PATH_WACKAMOLE_PIDDIR "/wackamole.pid");
    }
    snprintf(pidstring, 10, "%d\n", pid);
#ifdef BROKEN_SNPRINTF
    if(pidstring[9] != '\0') {
      pidstring[8] = '\n';
      pidstring[9] = '\0';
    }
#endif

    write(fd, pidstring, strlen(pidstring));
    close(fd);
    close(STDIN_FILENO);
    close(STDOUT_FILENO);
    close(STDERR_FILENO);
  }

  signalaction.sa_handler = Sig_handler;
  sigemptyset(&signalaction.sa_mask);
  signalaction.sa_flags = 0;


  if(sigaction(SIGINT, &signalaction, NULL)) {
    Alarm(EXIT, "An error occured while registering a SIGINT handler");
  }

  if(sigaction(SIGTERM, &signalaction, NULL)) {
    Alarm(EXIT, "An error occured while registering a SIGTERM handler");
  }
  if(sigaction(SIGBUS, &signalaction, NULL)) {
    Alarm(EXIT, "An error occured while registering a SIGBUS handler");
  }

  if(sigaction(SIGQUIT, &signalaction, NULL)) {
    Alarm(EXIT, "An error occured while registering a SIGQUIT handler");
  }

  if(sigaction(SIGSEGV, &signalaction, NULL)) {
    Alarm(EXIT, "An error occured while registering a SIGSEGV handler");
  }

  if_initialize();
  
  /* connecting to the relevant Spread daemon, asking for group info */
  Spread_reconnect(-8);
  
  Send_local_arp_cache_repeat();
  E_handle_events();
  return -1;
}

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

void  Handle_network()
{
  int ret;
  
  ret = SP_receive( Mbox, &Service_type, Sender, MAX_PSEUDO, &Num_groups, 
                Target_groups, &Mess_type, &Endian_mismatch, 
                MAX_MESS_LEN, Mess );
  if( ret < 0 )
    {
      SP_error( ret );
      Spread_reconnect(ret);
    }
  
  if( Is_membership_mess( Service_type ) )
    {
      if( Is_reg_memb_mess( Service_type ) )
      {
        Handle_membership();
        Send_local_arp_cache();
      }else{
        /* Ignore Transitional membership */
      }
    }else if( Is_regular_mess( Service_type ) ){
      
      /* Handle regular messages */
      if    ( Mess_type == STATE_MESS    ) Handle_state();
      else if     ( Mess_type == MATURING_MESS ) Handle_mature();
      else if     ( Mess_type == BALANCE_MESS  ) Handle_balance();
      else if     ( Mess_type == OPERATOR_MESS ) Handle_operator();
      else if     ( Mess_type == ARPCACHE_MESS ) Handle_arp_cache((int *)Mess,ret);
      
      /* Ignore messages of other types */
      
    }else{
      Alarm(EXIT,"Error: received message of unknown message type %d with ret %d",
           Service_type, ret );
     }
  
}

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

static      void  Turn_mature()
{
  int ret;
  
  ret = SP_multicast( Mbox, AGREED_MESS, Spread_group, MATURING_MESS, 0, 0 );
  if( ret < 0 )
    {
      SP_error( ret );
      Spread_reconnect(ret);
    }
  
  Alarm(LOGIC, "Turn_mature");
}

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

static      void  Handle_mature()
{
  if (Maturity == 1) return;
  
  Maturity = 1;
  E_dequeue( Turn_mature, 0, 0 );
  
  Alarm(LOGIC,"Handle_mature");
  if ( State != GATHER )
    {
      /* ### deterministically grab ip addresses */
      Priority_claim();
      Claim_unclaimed();
      Alarm(LOGIC, "Shifting to RUN in Handle_mature()" );
      State = RUN;
      E_queue( Balance, 0, 0, Balance_timer );
    }
}

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

static      void  Handle_operator()
{
  Alarm(LOGIC,"Handle_operator");
  
}

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

static      void  Handle_arp_cache(int *addresses, int size)
{
  int i;
  size /= sizeof(int);
  for(i=0;i<size;i++)
    insert_arp_cache_shared(ntohl(addresses[i]));
}

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

static      void  Handle_balance()
{
  int        i, j, k;
  int        num_bytes;
  int        *num_balanced;
  address    *curr_real_ptr;
  address    *curr_pseudo_ptr;

  Alarm(LOGIC,"Handle_balance");
  if( State != RUN ) return;
  Print_alloc();

  num_bytes = 0;
  num_balanced = (int *)&Mess[num_bytes];
  num_bytes += sizeof( int );
  if( Endian_mismatch ) *num_balanced = Flip_int32( *num_balanced );

  for ( k = 0; k < *num_balanced; k++ )
    {
      curr_real_ptr = (address *)&Mess[num_bytes];
      num_bytes += sizeof( address );
      curr_pseudo_ptr = (address *)&Mess[num_bytes];
      num_bytes += sizeof( address );

      if( Endian_mismatch )
      {
        *curr_real_ptr = Flip_int32( *curr_real_ptr );
        *curr_pseudo_ptr = Flip_int32( *curr_pseudo_ptr );
      }
        
      for ( i = 0; i < Num_pseudo; i++ )
      {
        if( *curr_pseudo_ptr == _pif_ip_s(Allocation_table[i]) )
          {
            if ( _rif_ip_s(My) == *curr_real_ptr )
            Acquire( &Allocation_table[i] );
            if ( _rif_ip_s(My) == _rif_ip_s(Allocation_table[i]) )
            Release( &Allocation_table[i] );
            for ( j = 0; j < Num_members; j++ )
            {
              if ( _rif_ip_s(Members[j]) == _rif_ip_s(Allocation_table[i]) )
                      Members[j].num_allocated--;
              if ( _rif_ip_s(Members[j]) == *curr_real_ptr )
                Members[j].num_allocated++;
            }
            _rif_ip_s(Allocation_table[i]) = *curr_real_ptr;
            i = Num_pseudo;
          }  
      }
    }
  
  Alarm(LOGIC,  "Finished Handle_balance." );
  Print_alloc();
}

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

static      void  Handle_membership()
{
  int i;
  
  Alarm(LOGIC, "Handle_membership");
  
  if( strcmp( Sender, Spread_group ) != 0 )
    {
      Bye();
      Clean_up();
      Alarm(EXIT, "Handle_membership:  Bug! got a membership for group %s",
           Sender );
      
    }
  
  memcpy( &Gid, Mess, sizeof( group_id ) );
  Num_pending_states = Num_groups;
  
  Num_members = Num_groups;

  for( i = 0; i < Num_members; i++ )
    {
      memcpy( Members[i].private_group_name, Target_groups[i], MAX_GROUP_NAME );
      /* RWC: SPREAD GIVES US THIS INFO, WHY WORK FOR IT? */
#if 0
      if( strcmp( Target_groups[i], Private_group ) == 0 ){
      My_index = i;
      }
#endif
      My_index = Mess_type;
      _rif_ip_s(Members[i]) = 0;
      Members[i].num_allocated = 0;
      Members[i].got_state_from = 0;
    }
  if(State != GATHER && State != BOOT)
    memcpy( Old_table, Allocation_table, MAX_PSEUDO * sizeof( entry ) );

  for ( i = 0; i < Num_pseudo; i++ )
    {
      _rif_ip_s(Allocation_table[i]) = 0;/* added 4/27/01 */
      Allocation_table[i].claim_priority = UNCLAIMED;
    }
  Send_state_message();       /* ### */
  Alarm(LOGIC,  "Shifting to GATHER" );
  State = GATHER;
  Alarm(LOGIC,  "Dequeuing Balance" ); /* Debug */
  E_dequeue( Balance, 0, 0 );

}

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

static      void  Handle_state()
{
  group_id  *curr_gid_ptr;
  address   *curr_real_address_ptr;
  int       num_bytes;
  int           *curr_index_ptr;
  int           *curr_maturity_ptr;
  int           *curr_num_allocated_ptr;  
  address       *curr_pseudo_addr_ptr;
  int           *curr_claim_priority_ptr;
  int           *curr_num_prefer_ptr;
  address       *curr_prefer_address;
  int           i, j, k;

  Alarm(LOGIC,  "Handle state" );

  num_bytes = 0;
  curr_gid_ptr = (group_id *)&Mess[num_bytes];
  num_bytes += sizeof( group_id );
  
  /* ### wackamole stuff */
  curr_real_address_ptr = (address *)&Mess[num_bytes];
  num_bytes += sizeof( address );
  curr_index_ptr = (int *)&Mess[num_bytes];
  num_bytes += sizeof( int );
  curr_maturity_ptr = (int *)&Mess[num_bytes];
  num_bytes += sizeof( int );
  curr_num_allocated_ptr = (int *)&Mess[num_bytes];
  num_bytes += sizeof( int );

  if( Endian_mismatch )
    {
      curr_gid_ptr->id[0] = Flip_int32( curr_gid_ptr->id[0] );
      curr_gid_ptr->id[1] = Flip_int32( curr_gid_ptr->id[1] );
      curr_gid_ptr->id[2] = Flip_int32( curr_gid_ptr->id[2] );
      
      /* ### wackamole stuff */
      *curr_real_address_ptr = Flip_int32( *curr_real_address_ptr );
      *curr_index_ptr = Flip_int32( *curr_index_ptr );
      *curr_maturity_ptr = Flip_int32( *curr_maturity_ptr );
      *curr_num_allocated_ptr = Flip_int32( *curr_num_allocated_ptr );
    }

  /* Check this here, don't process extra stuff if we don't need to. */
  if( Gid.id[0] != curr_gid_ptr->id[0] ||
      Gid.id[1] != curr_gid_ptr->id[1] ||
      Gid.id[2] != curr_gid_ptr->id[2] ) return;
  
  _rif_ip_s(Members[*curr_index_ptr]) = *curr_real_address_ptr;
  Members[*curr_index_ptr].num_allocated = *curr_num_allocated_ptr;
  Members[*curr_index_ptr].got_state_from = 1;

  /* Rip addresses and compute stuff */
  for ( i = 0; i < *curr_num_allocated_ptr; i++ )
    {
      curr_pseudo_addr_ptr = (address *)&Mess[num_bytes];
      num_bytes += sizeof( address );
      curr_claim_priority_ptr = (int *)&Mess[num_bytes];
      num_bytes += sizeof( int );
      if( Endian_mismatch )
      {
        *curr_pseudo_addr_ptr = Flip_int32( *curr_pseudo_addr_ptr );
        *curr_claim_priority_ptr = Flip_int32( *curr_claim_priority_ptr );
      }
      for ( j = 0; j < Num_pseudo; j++)
      {
        if ( *curr_pseudo_addr_ptr == _pif_ip_s(Allocation_table[j]) )
          {
            if( _rif_ip_s(Allocation_table[j]) == 0 )
            {
              _rif_ip_s(Allocation_table[j]) = *curr_real_address_ptr;
              Allocation_table[j].claim_priority = *curr_claim_priority_ptr;
            }
            else
            {/*conflict in ip address case*/
              if( Allocation_table[j].claim_priority == PREFER_CLAIMED ||
                  Allocation_table[j].claim_priority ==  *curr_claim_priority_ptr )
                {
                  Members[*curr_index_ptr].num_allocated--;
                  if( _rif_ip_s(My) == *curr_real_address_ptr )
                  {
                    ReleaseAddress(*curr_pseudo_addr_ptr);
                  }
                  Old_table[j].claim_priority = Allocation_table[j].claim_priority;
                  _rif_ip_s(Old_table[j]) = _rif_ip_s(Allocation_table[j]);
                }
              else if( Allocation_table[j].claim_priority == CLAIMED &&
                     *curr_claim_priority_ptr > PREFER )
                {
                  if( _rif_ip_s(My) == _rif_ip_s(Allocation_table[j]) )
                  ReleaseAddress( *curr_pseudo_addr_ptr );
                  for(k = 0; k < Num_members; ++k)
                  {
                    if( _rif_ip_s(Members[k]) == _rif_ip_s(Allocation_table[j]) )
                      Members[k].num_allocated--;
                  }
                  _rif_ip_s(Allocation_table[j]) = *curr_real_address_ptr;
                  Allocation_table[j].claim_priority = *curr_claim_priority_ptr;
                  Old_table[j].claim_priority = Allocation_table[j].claim_priority;
                  _rif_ip_s(Old_table[j]) = _rif_ip_s(Allocation_table[j]);
                }
            }
            j = Num_pseudo;
          }
      }
    }
  
  curr_num_prefer_ptr = (int *)&Mess[num_bytes];
  num_bytes += sizeof( int );
  if( Endian_mismatch ) *curr_num_prefer_ptr = Flip_int32( *curr_num_prefer_ptr );
  
  for ( i = 0; i < *curr_num_prefer_ptr; i++ )
    {
      curr_prefer_address = (address *)&Mess[num_bytes];
      num_bytes += sizeof( address );
      if( Endian_mismatch )
      *curr_prefer_address = Flip_int32( *curr_prefer_address );
      for ( j = 0; j < Num_pseudo; j++)
      if ( *curr_prefer_address == _pif_ip_s(Allocation_table[j]) )
        {
          if ( Allocation_table[j].claim_priority < PREFER )
            {
            _rif_ip_s(Allocation_table[j]) = *curr_real_address_ptr;
            Allocation_table[j].claim_priority = PREFER;
            }
          j = Num_pseudo;
        }
    }

  /* ### wackamole compute stuff */
  if ( Maturity == 0 && *curr_maturity_ptr == 1 )
    Handle_mature();
                           
  Alarm(LOGIC, "handle state:  got state from %d", *curr_real_address_ptr );
  Num_pending_states--;
  if( Num_pending_states == 0 )
    {
      Alarm(LOGIC,  "handle state: Finished getting states, maturity is %d.", Maturity );
      if ( Maturity ) 
      {
        /* wackamole calculate, drop and aquire */
        /* Do we do Priority_claim or Claim_unclaimed first? ... each has advantages. */
        Priority_claim();
        Claim_unclaimed();

        State = RUN;
        E_queue( Balance, 0, 0, Balance_timer );
        Alarm(LOGIC,  "handle state: shifting to RUN");
      }
      else
      {
        State = BOOT;
        Alarm(LOGIC,  "handle state: shifting back to BOOT");
      }
      Print_alloc();
    }
}

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

static      void  Send_state_message()
{
  int num_bytes;
  int ret;
  int   i;
  
  /* 
   * A State message looks like this:
   *  Gid
   *  real_address
   *    index
   *  maturity
   *  number of pseudo
   *        pseudo
   *        claim_priority
   *    number of  preferred pseudo
   *            pseudo
   */

  Alarm(LOGIC, "sending state");/*debug*/
  Print_alloc();
  num_bytes = 0;
  memcpy( &Mess[num_bytes], &Gid, sizeof( group_id ) );
  num_bytes += sizeof( group_id );
  memcpy( &Mess[num_bytes], &(_rif_ip_s(My)), sizeof( address ) );
  num_bytes += sizeof( address );
  memcpy( &Mess[num_bytes], &My_index, sizeof( int ) );
  num_bytes += sizeof( int );
  memcpy( &Mess[num_bytes], &Maturity, sizeof( int32 ) );
  num_bytes += sizeof( int32 );
  memcpy( &Mess[num_bytes], &My.num_allocated, sizeof( int32 ) );
  num_bytes += sizeof( int );

ret=0;
  for ( i = 0; i < Num_pseudo; i++ )
    {
      if ( _rif_ip_s(Old_table[i]) == _rif_ip_s(My) ) 
      {
        memcpy( &Mess[num_bytes], &(_pif_ip_s(Old_table[i])), sizeof( address ) );
        num_bytes += sizeof( address );
        memcpy( &Mess[num_bytes], &(Old_table[i].claim_priority), sizeof( int ) );
        num_bytes += sizeof( int );
ret++;
      }
    }
  assert(ret == My.num_allocated);
  memcpy( &Mess[num_bytes], &Num_prefer, sizeof( int ) );
  num_bytes += sizeof( int );

  for ( i = 0; i < Num_prefer; i++ )
    {
      memcpy( &Mess[num_bytes], &Prefer_address[i], sizeof( address ) );
      num_bytes += sizeof( address );
    }

  ret = SP_multicast( Mbox, AGREED_MESS, Spread_group, STATE_MESS, num_bytes, Mess );  
  if( ret < 0 )
    {
      SP_error( ret );
      Spread_reconnect(ret);
    }
}

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

static      void  Send_local_arp_cache_repeat()
{
  Send_local_arp_cache();
  E_queue( Send_local_arp_cache, 0, 0, ArpRefresh_timer );
}
static      void  Send_local_arp_cache()
{
  int ret, num_bytes=0;
  int *s, *addresses;
  int *d = (int *)Mess;

  sample_arp_cache();
  s = addresses = reference_private_arp_cache();

  while(*s && (char *)d < &Mess[MAX_MESS_LEN-sizeof(int)]) {
    *d = htonl(*s);
    d++; s++;
    num_bytes += sizeof(int);
  }
  Alarm(DEBUG, "Sending %d local arp entries", num_bytes/sizeof(int));
  ret = SP_multicast( Mbox, RELIABLE_MESS, Spread_group, ARPCACHE_MESS, num_bytes, Mess );  
  if( ret < 0 )
    {
      SP_error( ret );
      Spread_reconnect(ret);
    }
}

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

static  void    Priority_claim()
{
  int        i, j;
  Alarm(LOGIC,  "Priority_claim called" );
  for ( i = 0; i < Num_pseudo; i++ )
    {
      if ( Allocation_table[i].claim_priority == PREFER )
      {
        if ( _rif_ip_s(My) == _rif_ip_s(Allocation_table[i]) &&
             _rif_ip_s(My) != _rif_ip_s(Old_table[i]) )
          Acquire( &Allocation_table[i] );
        if ( _rif_ip_s(My) == _rif_ip_s(Old_table[i]) &&
             _rif_ip_s(My) != _rif_ip_s(Allocation_table[i]) )
          Release( &Allocation_table[i] );
        for ( j = 0; j < Num_members; j++ )
          {
            if ( _rif_ip_s(Members[j]) == _rif_ip_s(Old_table[i]) &&
               _rif_ip_s(Members[j]) != _rif_ip_s(Allocation_table[i]) )
            {
              Members[j].num_allocated--;
            }
            if ( _rif_ip_s(Members[j]) == _rif_ip_s(Allocation_table[i]) &&
               _rif_ip_s(Members[j]) != _rif_ip_s(Old_table[i]) )
            {
              Members[j].num_allocated++;
            }
          }
        Allocation_table[i].claim_priority = PREFER_CLAIMED;
      }
    }
  
  /** If we may need to revalidate num_allocated data. ***/
  if ( Maturity && !Old_maturity )
    {
      Old_maturity = 1;
      for ( i = 0; i < Num_members; i++ )
      {
        Members[i].num_allocated = 0;
        for ( j = 0; j < Num_pseudo; j++ )
          if ( _rif_ip_s(Allocation_table[j]) == _rif_ip_s(Members[i]) )
            Members[i].num_allocated++;
      }
    }
}

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

static  void    Claim_unclaimed()
{
  int         i, j;
  int         Member_to_claim;
  Alarm(LOGIC,  "Claim_unclaimed called" );
  for ( i = 0; i < Num_pseudo; i++ )
    if ( Allocation_table[i].claim_priority == UNCLAIMED )
      {
      Member_to_claim = 0;
        /* RWC: START COMPARING WITH INDEX 1, NOT INDEX 0 */
#if 0
        for ( j = 0; j < Num_members; j++ )
#endif
        for ( j = 1; j < Num_members; j++ )
        if ( Members[j].num_allocated < Members[Member_to_claim].num_allocated )
            Member_to_claim = j;
      if ( My_index == Member_to_claim )
        Acquire( &Allocation_table[i] );
      Members[Member_to_claim].num_allocated++;
      _rif_ip_s(Allocation_table[i]) = _rif_ip_s(Members[Member_to_claim]);
      Allocation_table[i].claim_priority = CLAIMED;
      }
}

/*************************************************/
static  entry  *findVEFromAddress( address Addr )
{
  int n;
  for(n=0; n<Num_pseudo; n++) {
    if(_pif_ip_s(Allocation_table[n]) == Addr)
      return &Allocation_table[n];
  }
  return NULL;
}
/* static  void    AcquireAddress( address Addr )
{
  entry *VE = findVEFromAddress(Addr);
  struct in_addr ipaddr;
  ipaddr.s_addr = Addr;
  if(!VE) {
    Alarm(PRINT, "AcquireAddress: Can't find VirtualInterface for: %s", inet_ntoa(ipaddr));
  } else {
    Acquire(VE);
  }
} */
static  void    Acquire( entry *VE )
{
  int ic, n=0;
  struct interface iface, *nif;

  for(nif=&VE->pseudo_if; n<MAX_DEP_IF; nif = &(VE->extra_ifs[n++])) {
      if(nif->ipaddr.s_addr == 0) break;
    memcpy(&iface, nif, sizeof(struct interface));
    iface.ipaddr.s_addr = htonl(iface.ipaddr.s_addr);
    iface.netmask.s_addr = htonl(iface.netmask.s_addr);
    iface.bcast.s_addr = htonl(iface.bcast.s_addr);
    ic = if_up(&iface);
    if(ic)
      Alarm(PRINT, "%s", if_error());
    else {
      char buffer[16];
      snprintf(buffer, 16, inet_ntoa(iface.ipaddr));
      Alarm(PRINT, "  UP: %s:%s/%s",
            iface.ifname,buffer,inet_ntoa(iface.netmask));
    }
  }
  invoke_spoofer(VE);
  My.num_allocated++;
}

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

static  void    ReleaseAddress( address Addr )
{
  entry *VE = findVEFromAddress(Addr);
  struct in_addr ipaddr;
  ipaddr.s_addr = Addr;
  if(!VE) {
    Alarm(PRINT, "ReleaseAddress: Can't find VirtualInterface for: %s", inet_ntoa(ipaddr));
  } else {
    Release(VE);
  }
}
static  void    Release( entry *VE )
{
  int ic, n=0;
  struct interface idown, *nif;

  for(nif=&VE->pseudo_if; n<MAX_DEP_IF; nif = &(VE->extra_ifs[n++])) {
      if(nif->ipaddr.s_addr == 0) break;
    memcpy(&idown, nif, sizeof(struct interface));
    idown.ipaddr.s_addr = htonl(idown.ipaddr.s_addr);
    idown.netmask.s_addr = htonl(idown.netmask.s_addr);
    idown.bcast.s_addr = htonl(idown.bcast.s_addr);
    ic = if_down(&idown);
    if(ic) {
      const char *em = if_error();
      if(em && strlen(em)) {
            Alarm(PRINT, "%s", if_error());
      }
    } else {
      char buffer[16];
      snprintf(buffer, 16, inet_ntoa(idown.ipaddr));
      Alarm(PRINT, "DOWN: %s:%s/%s",
      idown.ifname,buffer,inet_ntoa(idown.netmask));
    }
  }
  My.num_allocated--;
}


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

static  void    Balance()
{
  int          num_bytes;
  int          ret;
  int          i, j, k;
  int          min_index;
  int          max_index;
  member       tempMembers[MAX_PSEUDO];
  entry        tempTable[MAX_PSEUDO];
  Alarm(LOGIC, "Balance called." );

  if( My_index ) goto leave;

  if( State != RUN ) return;

  State = BALANCE;
  num_bytes = sizeof( int );

  min_index = 0;
  max_index = 0;

  memcpy( tempMembers, Members, MAX_PSEUDO * sizeof( member ) );
  memcpy( tempTable, Allocation_table, MAX_PSEUDO * sizeof( entry ) );

  for ( k = 0; k < Balance_rate; k++ )
    {
      for ( i = 0; i < Num_members; i++ )
      {
        if( tempMembers[i].num_allocated < tempMembers[min_index].num_allocated )
          min_index = i;
        if( tempMembers[i].num_allocated > tempMembers[max_index].num_allocated )
          max_index = i;
      }
      if( tempMembers[max_index].num_allocated - tempMembers[min_index].num_allocated > 1 )
      {
        for( j = 0; j < Num_pseudo; j++ )
          {
            if( _rif_ip_s(tempTable[j]) == _rif_ip_s(tempMembers[max_index])
              && tempTable[j].claim_priority < PREFER )
            {
              memcpy( &Mess[num_bytes], &(_rif_ip_s(tempMembers[min_index])), sizeof( address ) );
              num_bytes += sizeof( address );
              memcpy( &Mess[num_bytes], &(_pif_ip_s(tempTable[j])), sizeof( address ) );
              num_bytes += sizeof( address );
              tempMembers[min_index].num_allocated++;
              tempMembers[max_index].num_allocated--;
              _rif_ip_s(tempTable[j]) = _rif_ip_s(tempMembers[min_index]);
              j = Num_pseudo;
            }
            else if ( j == Num_pseudo )
            {
              if( k == 0 ) 
                {
                  State = RUN;
                  goto leave;
                }
              memcpy( &Mess[0], &k, sizeof( int ) );
              k = Balance_rate + 1;
            }
          }
      }
      else 
      {
        if( k == 0 ) 
          {
            State = RUN;
            goto leave;
          }
        memcpy( &Mess[0], &k, sizeof( int ) );  
        k = Balance_rate + 1;
      }
    }

  if ( k == Balance_rate )
      memcpy( &Mess[0], &k, sizeof( int ) );

  ret = SP_multicast( Mbox, AGREED_MESS, Spread_group, BALANCE_MESS, num_bytes, Mess );
  if( ret < 0 )
    {
      SP_error( ret );
      Spread_reconnect(ret);
    }
  State = RUN;
  Alarm(LOGIC, "Shifting to RUN in balance" );
 leave:
  if( !Complete_balance )
    E_queue( Balance, 0, 0, Balance_timer );
  return;
}

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

static      void    Wackamole_init()
{
  Alarm(LOGIC,"Wackamole_init");

  /* Set defaults */
  Maturity_timeout.sec = 5*60;
  Maturity_timeout.usec = 0;
  Balance_timer.sec = 5*60;
  Balance_timer.usec = 0;
  Balance_rate = 1;
  Complete_balance = 0;
  Spread_retry_interval = 5;

  spread_lock = 0;

  Get_conf(File_name, &My);

  /* start up control socket */
  create_control_socket(control_socket);

  if ( Balance_rate > Num_pseudo / 2)
    Balance_rate = Num_pseudo / 2;

  if( Complete_balance )
    {
      Balance_rate = Num_pseudo / 2;
      Balance_timer.sec = 0;
    }
}

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

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

static  void    Usage(int argc, char *argv[])
{

  /* Setting defaults */
  sprintf( User, "wack%d", (int)getpid() );
  sprintf( Spread_name, "4803" );

  while( --argc > 0 )
    {
      argv++;

      if( !strncmp( *argv, "-u", 2 ) )
      {
        strcpy( User, argv[1] );
        argc--; argv++;
      }else if( !strncmp( *argv, "-s", 2 ) ){
        strcpy( Spread_name, argv[1] );
        argc--; argv++;
      }else if(!strncmp(*argv, "-c", 2) ){
        if(argv[1][0] == '/')
          strcpy(File_name, argv[1]);
        else{
          getcwd(File_name,100);
          strcat(File_name,"/");      
          strcat(File_name, argv[1] );
            printf("%s", File_name);
        }
        argc--; argv++;
      }else if(!strncmp(*argv, "-d", 2) ){
        Debug = 1;
      }else{
        Alarm(EXIT, "Usage: wackamole\n%s\n%s\n%s",
              "\t[-u <private name>]  : unique (in this machine) private name",
              "\t[-s <address>]    : either port or port@machine"
              "\t[-c <confuguration file name>]   :file used instread of wackamole.conf");
      }
    }
}

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

static  void    Print_alloc()
{
#if 0
  int        i;
  address    Addr;
  char       IP[16];

  Alarm(LOGIC, "Current allocation table:" );
  for ( i = 0; i < Num_pseudo; i++ )
    {
      Addr = Allocation_table[i].pseudo_address;
      String_addr( Addr, IP );
      Alarm(LOGIC, "Pseudo address: %s", IP );
      Addr = Allocation_table[i].real_address;
      String_addr( Addr, IP );
      Alarm(LOGIC, "\tis allocated to %s with priority %d.", 
            IP, Allocation_table[i].claim_priority );
    }
#endif
}


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

/* static  void    String_addr( address Addr, char IP[16] )
{
  int one, two, three, four;

  one = (Addr & 0xff000000) >> 24;
  two = (Addr & 0x00ff0000) >> 16;
  three = (Addr & 0x0000ff00) >> 8;
  four = (Addr & 0x000000ff);
  sprintf(IP, "%d.%d.%d.%d", one, two, three, four );
} */

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

static void Sig_handler(int signum) {
  Alarm(DEBUG,"Sig_handler called");
  if(signum == SIGINT)
    Alarm(DEBUG, "SIGINT Detected!");
  if(signum == SIGTERM)
    Alarm(DEBUG,"SIGTERM Detected!");  
  if(signum == SIGBUS)
    Alarm(DEBUG,"SIGBUS Detected!");
  if(signum == SIGQUIT) 
    Alarm(DEBUG,"SIGQUIT Detected!");  
  if(signum == SIGSEGV) 
    Alarm(DEBUG,"SIGSEGV Detected!");

  Clean_up();
  global_exit = 1;
  exit(0);
}


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

void Clean_up(){
  
  int cl_index;
  Alarm(DEBUG, "Clean_up called");
 
  for(cl_index = 0; cl_index < Num_pseudo; cl_index++){
    cancel_spoofer(&Old_table[cl_index]);
    Release(&Old_table[cl_index]);
    Allocation_table[cl_index].real_if.ipaddr.s_addr = 0;
    Old_table[cl_index].real_if.ipaddr.s_addr = 0;
  }
}

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

void    handle_reconnect(int a, void *d) {
  sp_time delay;
  delay.sec = Spread_retry_interval;
  delay.usec = 0;
  E_queue((void(*)(int, void *))Spread_reconnect, -2, NULL, delay);
}
void    Spread_reconnect(int ret){

  if(ret != -8 && ret != -11 && ret != -2)
    Alarm(EXIT, "Spread_reconnnect: Unexpected Error (%d)", ret);
  
  Alarm(PRINT,"connecting to %s", Spread_name);
    
  Clean_up();

  if(Mbox >= 0) {
    SP_disconnect(Mbox);
    E_detach_fd( Mbox, READ_FD );
    Mbox = -1;
  }
  /* connecting to the relevant Spread daemon, asking for group info */
  if(spread_lock)
    return handle_reconnect(0, NULL);
  ret = SP_connect( Spread_name, User, 0, 1, &Mbox, Private_group ) ;
  if(ret == ACCEPT_SESSION) {
    ret = SP_join( Mbox, Spread_group );  
    if( ret < 0 ) {
      SP_error( ret );
      SP_disconnect( Mbox );
      Mbox = -1;
      Alarm(PRINT, "Spread join on reconnect failed [%d].", ret);
      return handle_reconnect(0, NULL);
    }
  } else {
    Alarm(PRINT, "Spread connect failed [%d].", ret);
    return handle_reconnect(0, NULL);
  }

  /* State initializations */
  State = BOOT;
  Old_maturity = 0;
  Maturity = 0;
  E_queue( Turn_mature, 0, 0, Maturity_timeout );
  My.num_allocated = 0;
  
  strcpy(My.private_group_name, Private_group);

  E_attach_fd( Mbox, READ_FD, Handle_network, 0, NULL, HIGH_PRIORITY );
  E_set_active_threshold( HIGH_PRIORITY );
}


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

void Bye(){
  Alarm(DEBUG, "Disconnecting from Spread");
  SP_disconnect(Mbox);
}

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

Generated by  Doxygen 1.6.0   Back to index