On 2002-06-21 03:09 +0000, Giorgos Keramidas wrote:
> Below is a prototype I'm playing the last few days with, trying to
> make something that implements the above scheme using <queue.h>
> macros.  Now, what do you all think about this?  Does it sound like a
> nice idea to pursue further?

It would be nice if I also included the source *grin*

%%%
#include <netinet/in.h>
#include <sys/queue.h>
#include <sys/types.h>
#include <assert.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

LIST_HEAD(cpidhead, childpid);
struct childpid {
        pid_t cp_pid;                   /* Process ID of a child. */
        LIST_ENTRY(childpid) cp_entry;  /* Glue to the other list elements. */
};

LIST_HEAD(ciphead, childaddr);
struct childaddr {
        struct in_addr ca_addr;         /* Address of a host. */
        int ca_count;                   /* Number of items in pid list. */
        struct cpidhead ca_pid;         /* Head of the PID list. */
        LIST_ENTRY(childaddr) ca_entry; /* Glue to the other list elements. */
};

/*
 * This hash keeps a number of pointers to `ciphead' lists.
 * Use the iphash() function to find the proper element of this array
 * for the records related to an IP address.
 */
struct ciphead *ciphash[UINT16_MAX];

static unsigned short iphash(struct in_addr *paddr);
static struct childaddr *cip_find(struct ciphead *ph, struct in_addr *addr);
static struct childaddr *cip_add(struct ciphead *ph, struct in_addr *addr);
static struct childpid *cpid_find(struct cpidhead *ph, pid_t pid);
static struct childpid *cpid_add(struct childaddr *pa, pid_t pid);

int
main(void)
{
        struct in_addr lo;
        struct childaddr *pa;
        struct childpid *pp;
        uint16_t hval;

        /* Add the address of localhost to the proper place in ciphash[]. */
        lo.s_addr = htonl(0x7f000001);
        hval = iphash(&lo);
        if (ciphash[hval] == NULL) {
                ciphash[hval] = malloc(sizeof(struct ciphead));
                if (ciphash[hval] == NULL)
                        exit(1);
        } else
                LIST_INIT(ciphash[hval]);

        pa = cip_find(ciphash[hval], &lo);
        if (pa == NULL && (pa = cip_add(ciphash[hval], &lo)) == NULL) {
                if (LIST_FIRST(ciphash[hval]) == NULL)
                        free(ciphash[hval]);
                exit(1);
        }

        /* Add the PID to the list `pa->ca_pid'. */
        cpid_add(pa, getpid());

        /* Print the mess we created so far. */
        printf("%p: struct ciphead {\n", ciphash[hval]);
        printf("        lh_first = %p,\n", pa = LIST_FIRST((ciphash[hval])));
        printf("};\n");
        printf("\n");
        printf("%p: struct childaddr {\n", pa);
        printf("        ca_addr = 0x%08x,\n", (pa->ca_addr).s_addr);
        printf("        ca_count = %d,\n", pa->ca_count);
        printf("        ca_pid = %p,\n", &(pa->ca_pid));
        printf("};\n");
        printf("\n");
        printf("%p: struct cpidhead {\n", &(pa->ca_pid));
        printf("        lh_first = %p,\n", pp = LIST_FIRST((&(pa->ca_pid))));
        printf("};\n");
        printf("\n");
        printf("%p: struct childpid {\n", pp);
        printf("        pid = %d,\n", pp->cp_pid);
        printf("};\n");
        printf("\n");

        return (0);
}

/*
 * Return a very simple XOR-based hash value, derived from the bytes of a
 * `struct in_addr' structure.
 */

static uint16_t
iphash(struct in_addr *paddr)
{
        uint16_t *sp;
        uint16_t val;
        size_t len;
        size_t k;

        assert(paddr != NULL);
        sp = ((uint16_t *) paddr);

        val = 0;
        len = sizeof(struct in_addr) / sizeof(uint16_t);
        if (len == 0 || len == 1) {
                val = 0xffff;
        } else {
                for (k = 0; k < len; k++)
                        val ^= sp[k];
                val &= 0xffff;
        }

        return (val);
}

/*
 * Look in all the elements of `ph' and see if they match `addr'.
 * Return the address of the first match, or NULL if none is found.
 */

static struct childaddr *
cip_find(struct ciphead *ph, struct in_addr *addr)
{
        struct childaddr *pa;

        assert(ph != NULL && addr != NULL);

        LIST_FOREACH(pa, ph, ca_entry)
                if ((pa->ca_addr).s_addr == (*addr).s_addr)
                        return (pa);
        return (NULL);
}

/*
 * Add a new address structure, in the list of childaddr's pointed at by
 * the `ph' list head.  This doesn't check for an existing match, so
 * duplicates might end up in your list, if you don't use cip_find() first to
 * look for older matches.
 */

struct childaddr *
cip_add(struct ciphead *ph, struct in_addr *addr)
{
        struct childaddr *pa;

        assert(ph != NULL && addr != NULL);

        /* Try to allocate a new childaddr record. */
        if ((pa = malloc(sizeof(struct childaddr))) == NULL)
                return (NULL);

        pa->ca_addr = *addr;
        pa->ca_count = 0;
        LIST_INIT(&(pa->ca_pid));
        LIST_INSERT_HEAD(ph, pa, ca_entry);
        return (pa);
}

/*
 * Look in the list of childpid records pointed at by `ph' for the given PID.
 * Return a pointer to the proper (struct childpid) or NULL if a match can not
 * be found at all.
 */

static struct childpid *
cpid_find(struct cpidhead *ph, pid_t pid)
{
        struct childpid *p;

        assert(ph != NULL);

        LIST_FOREACH(p, ph, cp_entry)
                if (p->cp_pid == pid)
                        return (p);
        return (NULL);
}

/*
 * Add a new PID to the list of process IDs help under `pa'.
 */

static struct childpid *
cpid_add(struct childaddr *pa, pid_t pid)
{
        struct childpid *pp;
        struct cpidhead *ph;

        assert(pa != NULL);

        ph = &(pa->ca_pid);
        pp = cpid_find(ph, pid);
        if (pp == NULL) {
                pp = malloc(sizeof(struct childpid));
                if (pp == NULL)
                        return (NULL);
                pp->cp_pid = pid;
                LIST_INSERT_HEAD(ph, pp, cp_entry);
                pa->ca_count++;
                return pp;
        }

        return (NULL);
}
%%%

Attachment: msg35117/pgp00000.pgp
Description: PGP signature

Reply via email to