const char addrlist_rcs[] = "$Id: addrlist.c,v 1.2 2003/06/19 15:58:58 lionel Exp $";
/*********************************************************************
 *
 * File        :  $Source: /ds6/cvs/privoxy/src/addrlist.c,v $
 *
 * Purpose     :  Declares functions to handle lists of network addresses.
 *                Functions declared include:
 *                   `destroy_addr_list', head_addr_list and `tail_addr_list'
 *
 * Copyright   :  Written by and Copyright (C) 2002 Lionel Elie Mamane
 *                <lionel@mamane.lu>
 *
 *                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.
 *
 *                The GNU General Public License should be included with
 *                this file.  If not, you can view it at
 *                http://www.gnu.org/copyleft/gpl.html
 *                or write to the Free Software Foundation, Inc., 59
 *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * Revisions   :
 *    $Log: addrlist.c,v $
 *    Revision 1.2  2003/06/19 15:58:58  lionel
 *    Fix mask calculation in fill_acl_addr_mask in IPv6 case
 *    Where there's a sockaddr, there's an addrlen. Fixes portability to (Free)BSD.
 *
 *    Revision 1.1  2003/05/23 17:03:47  lionel
 *    Address list implementation
 *
 *
 *********************************************************************/

#include "addrlist.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>

/*********************************************************************
 *
 * Function    :  acceptable
 *
 * Description :  Test wheter an address is acceptable for our use
 *                Currently, this means either an IPv4 or an IPv6 address
 *
 * Parameters  :
 *          0  :  addr = the address to test
 *
 * Returns     :  0             = false / no
 *                anything else = true / yes
 *
 *********************************************************************/
static int acceptable (struct sockaddr_storage *addr)
{
   switch(addr->ss_family)
   {
   case AF_INET:
#ifdef INET6
   case AF_INET6:
#endif
      return !0;
   default:
      return 0;
   }
}

/*********************************************************************
 *
 * Function    :  skim
 *
 * Description :  Get the first acceptable address in head position
 *                Assumes there is one
 *
 * Parameters  :
 *          0  :  l = the list to skim
 *
 * Returns     :  the skimmed list
 *
 *********************************************************************/
static addr_list *skim (addr_list *l)
{
   if (acceptable((struct sockaddr_storage*)l->ai_addr))
      return l;
   return skim(l->ai_next);
}

/*********************************************************************
 *
 * Function    :  tail_addr_list
 *
 * Description :  Get the tail of an address list
 *
 * Parameters  :
 *          0  :  l = the list to get the tail of
 *
 * Returns     :  the tail of the list
 *                If the list has no tail (i.e. is nil), unspecified
 *                behaviour
 *
 *********************************************************************/
addr_list *tail_addr_list(addr_list *l)
{
   return skim(l)->ai_next;
}

/*********************************************************************
 *
 * Function    :  head_addr_list
 *
 * Description :  Get the head of an address list
 *
 * Parameters  :
 *          0  :  l = the list to get the head of
 *
 * Returns     :  the head of the list
 *                If the list has no head (i.e. is nil), unspecified
 *                behaviour
 *
 *********************************************************************/
struct sockaddr_storage *head_addr_list(addr_list *l)
{
   return (struct sockaddr_storage *)skim(l)->ai_addr;
}

/*********************************************************************
 *
 * Function    :  cpy_head_addr_list
 *
 * Description :  Copy the head of an address list to the given destination
 *
 * Parameters  :
 *          0  :  l = the list to get the head of
 *          1  :  r = where to put the result
 *
 * Returns     :  Nothing
 *                If the list has no head (i.e. is nil), unspecified
 *                behaviour
 *
 *********************************************************************/
void cpy_head_addr_list(addr_list *l, struct sockaddr_storage *r, size_t *addrlen)
{
   addr_list *sl = skim(l);
   memcpy(r, sl->ai_addr, sl->ai_addrlen);
   *addrlen = sl->ai_addrlen;
}

/*********************************************************************
 *
 * Function    :  destroy_addr_list
 *
 * Description :  Unallocate memory allocated to an address list
 *
 * Parameters  :
 *          0  :  l = the list to unallocate
 *
 * Returns     :  nothing
 *
 *********************************************************************/
void destroy_addr_list(addr_list *l)
{
   freeaddrinfo(l);
}

/*********************************************************************
 *
 * Function    :  is_nil_addr_list
 *
 * Description :  Test wheter a list is nil (empty)
 *
 * Parameters  :
 *          0  :  l = the list to test
 *
 * Returns     :  0             = false if list has a head,
 *                anything else = true if list is nil
 *
 *********************************************************************/
int is_nil_addr_list(addr_list *l)
{
   /* We are searching for a witness of non-nilness (modulo acceptability)
    * If none is found, the list is nil
    */
   if (l==NULL)
      /* Empty list*/
      return !0;
   if (acceptable(head_addr_list(l)))
      /* Witness found */
      return 0;
   return is_nil_addr_list(l->ai_next);
}

/*
  Local Variables:
  tab-width: 3
  c-file-style: "stroustrup"
  c-basic-offset: 3
  indent-tabs-mode: nil
  end:
*/
