
/****************************************************************************/
/*                                                                          */
/*      NNstat -- Internet Statistics Collection Package                    */
/*                                                                          */
/*            Written by: Bob Braden & Annette DeSchon                      */
/*            USC Information Sciences Institute                            */
/*            Marina del Rey, California                                    */
/*                                                                          */
/*      Copyright (c) 1991 University of Southern California.               */
/*      All rights reserved.                                                */
/*                                                                          */
/*      Redistribution and use in source and binary forms are permitted     */
/*      provided that the above copyright notice and this paragraph are     */
/*      duplicated in all such forms and that any documentation,            */
/*      advertising materials, and other materials related to such          */
/*      distribution and use acknowledge that the software was              */
/*      developed by the University of Southern California, Information     */
/*      Sciences Institute.  The name of the University may not be used     */
/*      to endorse or promote products derived from this software           */
/*      without specific prior written permission.                          */
/*      THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR        */
/*      IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED      */
/*      WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR          */
/*      PURPOSE.                                                            */
/*                                                                          */
/****************************************************************************/

static char rcsid[]=
  "$Header: /tmp_mnt/r/jove_staff3/mogul/alpha/code/NNstat/RCS/filter.c,v 1.5 1993/08/31 23:45:40 mogul Exp $";
 
/* CHANGES:
 *   17Nov88 RTB: Add EQ object
 *      Rel 3.0:
 *   ISI:  Add List routines.
 *   ISI:  Read commands for RF, EQ display the comparands.
 *   ISI:  Add 3rd parameter -- mask -- to RF and fix bugs.
 *   DEC/ISI: Little-endian changes   
 *   Aug93/DECWRL: Alpha/OSF port.  XDR is a pointer type.  Fixed
 *	some bugs associated with printing filter values.
 */
 
/*
 *   Internet Statistics Facility -- Generic Operation Routines
 *
 *    This module defines filter objects, which can examine given values
 *    and make a choice of alternative sets of calls on recording Statistical
 *    Objects.
 *
 *    These filters are constructed as abstract objects, to parallel
 *    the form of the recording Statistical Objects.  They keep simple
 *    counts of total packets and true choices (the difference being the
 *    false-choice count).
 */
 
#include <stdio.h>
#include <sys/types.h>
#include "stat.h"
#include "sobj.h"
 
/*
 *
 *          RF Object Class ==  RANGE-CHECK FILTER 
 *
 *    Objects of the RF class are filters that check that the given field
 *    value falls outside a specified range.
 *
 *    Operations on RF class objects:
 *
 *       SOBJ *Make_RF( objname, &{L [,U [,mask]]}, nparms, datalen )
 *
 *           If U omitted, use U == L
 *           If mask omitted, use -1
 *
 *       int Write_RF( (SOBJ *) SOBJ-ptr, &value , length)
 *
 *           => True if:  L <= Value&Mask <= U.
 *
 *       Read_RF( fd, (SOBJ *) SOBJ-ptr )
 *
 *       Clear_RF(  (SOBJ *) SOBJ-ptr )
 *
 *       Delete_RF(  (SOBJ *) SOBJ-ptr )
 *
 *       List_filter( fd, OBJp )
 *
 *
 */
    

SOBJ *Make_RF() ;
int  Write_RF(), Read_RF();
void Clear_RF(), Delete_RF(), List_filter() ;

        /*   Transfer Vector 
         *   for external access to these routines
         */
GENERICOP RFop = { Make_RF, Write_RF, Read_RF, Clear_RF, Delete_RF, List_filter} ;

#define RFA struct stat_farea
RFA {
    SOBJ  rfa_sobj ;
        
    int32  rfa_trueno ;
    union v_union rfa_ULvals;  /* L, U values.  These are stored like parms,
                                *   right-justified in fullword for L <= 4,
                                *   else left-justified.
                                */
    union v_union rfa_Mval;    /* Mask value */
} ;

#define rfa_L  rfa_ULvals.v_ul.v_ul1
#define rfa_U  rfa_ULvals.v_ul.v_ul3
#define rfa_Lb rfa_ULvals.v_byte[0]
#define rfa_Ub rfa_ULvals.v_byte[MAX_DLENG]
#define rfa_M  rfa_Mval.v_ul.v_ul1

 
SOBJ *Make_RF(objname, parmp, nparms, datalen)
    char *objname;
    u_int32 *parmp ;
    int datalen, nparms;
    {
    u_int32 *parmp0 = parmp;
    register RFA *rfap;
    
    nparms /= ALIGN(datalen)/4;
    if (nparms == 0) {
        SOBJ_error = "RF: missing parms";
        return(NULL);
    }
    else if (nparms > 3) {
        SOBJ_error = "RF: too many parms";
        return(NULL);
    }
    
    if ((rfap = (RFA *) malloc(sizeof(RFA))) == NULL) {
        SOBJ_error = "RF: memory shortage";
        return(NULL) ;
    } 
    
    Clear_RF(rfap);
    WORD1(&rfap->rfa_ULvals) = *parmp++;
    if (datalen > sizeof(u_int32))
        WORD2(&rfap->rfa_ULvals) = *parmp++;
    WORD3(&rfap->rfa_ULvals) = (nparms > 1)? *parmp++ : WORD1(&rfap->rfa_ULvals);
    if (datalen > sizeof(u_int32))
        WORD4(&rfap->rfa_ULvals) = 
                               (nparms > 1)? *parmp++ : WORD2(&rfap->rfa_ULvals);
        
    WORD1(&rfap->rfa_Mval) = WORD2(&rfap->rfa_Mval) = 0xffffffff; /* default mask*/
    if (nparms == 3) {
        WORD1(&rfap->rfa_Mval) = *parmp++;
        if (datalen > sizeof(u_int32))
            WORD2(&rfap->rfa_Mval) = *parmp++;
    }
    return(&rfap->rfa_sobj) ;
}


int Write_RF(rfap, Valuep, L)
    register RFA  *rfap ;
    char *Valuep ;
    int L;
    {
    register int N = L;
    union v_union Value;
    u_int32 x1, x2; 
    
    if (L > sizeof(u_int32)) {
    
#ifdef  LITTLEEND
        register char *vp = Valuep, 
                      *mp = (char *) rfap->rfa_Mval.v_byte, 
                      *rp = Value.v_byte;
            /* Copy and mask the value */
        while (--N >= 0)
            *rp++ = *vp++ & *mp++;
        
        if (strncmp(Value.v_byte, &rfap->rfa_Lb, L) >= 0 &&
            strncmp(Value.v_byte, &rfap->rfa_Ub, L) <= 0)  {
#else
        ZERO_UNION(&Value);
        bcopy(Valuep, Value.v_byte, N);
        x1 = WORD1(&Value) & WORD1(&rfap->rfa_Mval);
        x2 = WORD2(&Value) & WORD2(&rfap->rfa_Mval);
        if ((
             WORD1(&rfap->rfa_ULvals) < x1 ||  
               (WORD1(&rfap->rfa_ULvals) == x1 && WORD2(&rfap->rfa_ULvals) <= x2 )
            ) && (     
             x1 < WORD3(&rfap->rfa_ULvals) ||  
               (x1 == WORD3(&rfap->rfa_ULvals) && x2 <= WORD4(&rfap->rfa_ULvals) ))
           )  {
#endif
            rfap->rfa_trueno++;
            return(WRRET_TRUE);
        } 
    }     
    else {  /* The following should work for either-endian */
        x1 = ntohl(WORD1(&rfap->rfa_Mval)) & (LFETCH(Valuep, N));
        if (x1 >= ntohl(rfap->rfa_L) && x1 <= ntohl(rfap->rfa_U))  {
            rfap->rfa_trueno++;
            return(WRRET_TRUE);
        }
    }
                       
    return(WRRET_FALSE ) ; 
} /* Write_RF() */


void Clear_RF(rfap)
    RFA  *rfap ;
    {
    rfap->rfa_trueno = 0 ;
}


void Delete_RF(rfap)
    RFA  *rfap ;
    {
    free(rfap) ;
}


boolean Read_RF(fd, rfap)
    XDR *fd;
    RFA *rfap ;
    { 
    int L;
                        
    if (!PutReadResp(fd, RFr_SIZE, &rfap->rfa_sobj) ) return(FALSE);
    
    if (ISTTY(fd)) {
        printf("  TRUE no= %d for range: (",  rfap->rfa_trueno);
        if ((L = rfap->rfa_sobj.sob_dleng) > sizeof(u_int32)) {
            char out[4*MAX_DLENG + 6];
            print_val(out, &rfap->rfa_L, DTYP_bits, L);
            printf("%s, ", out);
            print_val(out, &rfap->rfa_U, DTYP_bits, L);
            printf("%s)\n", out);
        }
        else
            printf("%d, %d)\n", ntohl(rfap->rfa_L), ntohl(rfap->rfa_U)); 
    }
    else {
        if (!xdr_int(fd, &rfap->rfa_trueno)) return(FALSE) ;  
    }
    return(TRUE);     
}

void List_filter(fd, OBJp)
    XDR *fd;
    OBJ *OBJp;
    {
    char fout[256];
    get_long(fd, fout, "  #TRUE");
    log(fout, logfp);
}
    
  
/*
 *
 *          SF Object Class ==  SET-CHECK FILTER 
 *
 *    Objects of the SF class filter by checking whether a given field
 *    value is a member of a specified set of values.
 *
 *    SF objects are implemented using a precomputed open hashing.  When
 *    the table is computed it tries to choose a hash table large enough
 *    to get "perfect" hashing. 
 *
 *
 *    Operations on SF class objects:
 *
 *       SOBJ *Make_SF( object-name, &valuelist[#bins], #values, datalen  )
 *
 *       int Write_SF( (SOBJ *) SOBJ-ptr, &value , length)
 *             Returns TRUE if value falls into given set.
 *
 *       Read_SF( fd, (SOBJ *) SOBJ-ptr )
 *
 *       Delete_SF( (SOBJ *) SOBJ-ptr )
 *
 *       Clear_SF( (SOBJ *) SOBJ-ptr )
 *
 *    THIS CLASS USES THE ROUTINES OF CLASS FO (FREQ-ONLY).
 */
    
extern SOBJ *Make_FO() ;
extern boolean  Search_FO();
extern u_int32 BinCount_FO();
boolean Read_SF();
void  Clear_FO(), Delete_FO() ;

    /* Transfer Vector 
     *   for external access to these routines
     */
GENERICOP SFop = { Make_FO, Search_FO, Read_SF, Clear_FO, Delete_FO, List_filter } ;


int Read_SF(fd, sfap)
    XDR *fd;
    SOBJ *sfap;
    {   
    u_int32 trueno = BinCount_FO(sfap) ;
    
    if (!PutReadResp(fd, SFr_SIZE, sfap) ) return(FALSE);
    
    if (ISTTY(fd))
        printf("  TRUE no= %d\n", trueno);
    else {
        if (!xdr_int(fd, &trueno)) return(FALSE) ;  
    }
    return(TRUE);                     
}
 
  
/*
 *
 *          EQ Object Class ==  EQUALITY FILTER 
 *
 *    Objects of the EQ class filter by checking whether a given field
 *    value is equal to a specified value.
 * *
 *
 *    Operations on EQ class objects:
 *
 *       SOBJ *Make_EQ( object-name, &value, 1, datalen  )
 *
 *       int Write_EQ( (SOBJ *) SOBJ-ptr, &value , length)
 *             Returns TRUE if value falls into given set.
 *
 *       Read_EQ( fd, (SOBJ *) SOBJ-ptr )
 *
 *       Delete_EQ( (SOBJ *) SOBJ-ptr )
 *
 *       Clear_EQ( (SOBJ *) SOBJ-ptr )
 *
 */
     

SOBJ *Make_EQ() ;
int  Write_EQ(), Read_EQ();
void Clear_EQ(), Delete_EQ() ;

        /*   Transfer Vector 
         *   for external access to these routines
         */
GENERICOP EQop = { Make_EQ, Write_EQ, Read_EQ, Clear_EQ, Delete_EQ, List_filter } ;

#define EQA struct stat_eqarea
EQA {
    SOBJ  eqa_sobj ;
        
    int32  eqa_trueno ;
    char  eqa_val[MAX_DLENG];  /* Comparison Value */
} ;

 
SOBJ *Make_EQ(objname, parmp, nparms, datalen)
    char *objname;
    u_int32 *parmp ;
    int datalen, nparms;
    {
    EQA *eqap;
    int offset =  PARMALIGN(datalen);
    int len = ALIGN(datalen);
    u_char *pp = (u_char *) parmp + offset;
    
    if (nparms == 0 || nparms > 2) {
        SOBJ_error = "EQ: wrong # parms";
        return(NULL);
    }
    if ((eqap = (EQA *) malloc(sizeof(EQA))) == NULL) {
        SOBJ_error = "EQ: memory shortage";
        return(NULL) ;
    } 
    
    Clear_EQ(eqap);
    bcopy(pp, eqap->eqa_val, len);
    return(&eqap->eqa_sobj) ;
}


int Write_EQ(eqap, Valuep, L)
    EQA  *eqap ;
    register char *Valuep ;
    register int L;
    { 
    register char *cp = &eqap->eqa_val[0]; 
    
    while (L-- > 0) 
    	if (*Valuep++ != *cp++) return(WRRET_FALSE);

    eqap->eqa_trueno++;
    return(WRRET_TRUE) ; 
}

void Clear_EQ(eqap)
    EQA  *eqap ;
    {
    eqap->eqa_trueno = 0 ;
}


void Delete_EQ(eqap)
    EQA  *eqap ;
    {
    free(eqap) ;
}


int Read_EQ(fd, eqap)
    XDR *fd;
    EQA *eqap ;
    { 
    int L;
                        
    if (!PutReadResp(fd, SFr_SIZE, &eqap->eqa_sobj) ) return(FALSE);
    
    if (ISTTY(fd)) {
        printf("  TRUE no= %d for value: ", eqap->eqa_trueno);
        if ((L = eqap->eqa_sobj.sob_dleng) > sizeof(u_int32)) {
            char out[2*MAX_DLENG + 3];
            print_val(out, eqap->eqa_val, DTYP_bits, L);
            printf("%s\n", out);
        }
        else
            printf("%d ", *((u_int32 *)eqap->eqa_val));
            printf("[0x%x]\n", *((u_int32 *)eqap->eqa_val));
    }
    else {
        if (!xdr_int(fd, &eqap->eqa_trueno)) return(FALSE) ;  
    }
    return(TRUE);     
}
    
  
