/*
 * Copyright (c) 2012-2014 Red Hat.
 * Copyright (c) 1997-2001 Silicon Graphics, Inc.  All Rights Reserved.
 */

/* Check all ops except one turned off for all combinations.
 * Check connection limits
 */

#include <pcp/pmapi.h>
#include "libpcp.h"
#include "localconfig.h"

int
main(int argc, char **argv)
{
    int			s, sts, op, host;
    unsigned int	i;
    char		name[4*8 + 7 + 1]; /* handles full IPv6 address, if supported */
    int			ipv4 = -1;
    int			ipv6 = -1;
    int			errflag = 0;
    int			c;
    __pmSockAddr	*inaddr;

    /* trim cmd name of leading directory components */
    pmSetProgname(argv[0]);

    while ((c = getopt(argc, argv, "46D:?")) != EOF) {
	switch (c) {

	case '4':	/* ipv4 (default) */
	    ipv4 = 1;
	    break;

	case '6':	/* ipv6 */
	    ipv6 = 1;
	    break;

	case 'D':	/* debug options */
	    sts = pmSetDebug(optarg);
	    if (sts < 0) {
		fprintf(stderr, "%s: unrecognized debug options specification (%s)\n",
		    pmGetProgname(), optarg);
		errflag++;
	    }
	    break;

	case '?':
	default:
	    errflag++;
	    break;
	}
    }

    if (errflag) {
	fprintf(stderr,
"Usage: %s [options]\n\
\n\
Options:\n\
  -4             do IPv4 (default)\n\
  -6		 do IPv6\n",
                pmGetProgname());
        return 1;
    }

    /* defaults */
    if (ipv4 == -1) ipv4 = 1;
    if (ipv6 == -1) ipv6 = 0;

    sts = 0;
    for (op = 0; op < WORD_BIT; op++)
	if ((s = __pmAccAddOp(1 << op)) < 0) {
	    printf("Bad op %d: %s\n", op, strerror(errno));
	    sts = s;
	}

    if (sts < 0)
	return 1;


    for (host = 0; host < WORD_BIT; host++) {
	if (ipv4) {
	    pmsprintf(name, sizeof(name), "155.%d.%d.%d", host * 3, 17+host, host);
	    if ((s = __pmAccAddHost(name, ~(1 << host), ~(1 << host), host)) < 0) {
		printf("cannot add inet host for op%d: %s\n", host, strerror(s));
		sts = s;
	    }
	}
	if (ipv6) {
	    pmsprintf(name, sizeof(name), "fec0::%x:%x:%x:%x:%x:%x",
		    host * 3, 17+host, host,
		    host * 3, 17+host, host);
	    if ((s = __pmAccAddHost(name, ~(1 << host), ~(1 << host), host)) < 0) {
		printf("cannot add IPv6 host for op%d: %s\n", host, strerror(s));
		sts = s;
	    }
	}
    }
    if (sts < 0)
	return 1;

    putc('\n', stderr);

    putc('\n', stderr);
    __pmAccDumpHosts(stderr);

    putc('\n', stderr);

    if (ipv4) {
	for (host = 0; host < WORD_BIT; host++) {
	    int	j;

	    for (j = 0; j <= host; j++) {
		char	buf[20];
		pmsprintf(buf, sizeof(buf), "%d.%d.%d.%d", 155, host * 3, 17+host, host);
		if ((inaddr =__pmStringToSockAddr(buf)) == NULL) {
		  printf("insufficient memory\n");
		  continue;
		}
		sts = __pmAccAddClient(inaddr, &i);
		__pmSockAddrFree(inaddr);
		if (sts < 0) {
		    if (j == host && sts == PM_ERR_CONNLIMIT)
			continue;
		    printf("add inet client from host %d (j=%d): %s\n",
			   j, host, pmErrStr(sts));
		    continue;
		}
		else if (i != (~(1 << host)))
		    printf("inet host %d: __pmAccAddClient returns denyOpsResult 0x%x (expected 0x%x)\n",
			   host, i, ~(1 << host));
	    }
	}
    }
    if (ipv6) {
	for (host = 0; host < WORD_BIT; host++) {
	    int	j;

	    for (j = 0; j <= host; j++) {
		char	buf[4*8 + 7 + 1]; /* handles full IPv6 address */
		pmsprintf(buf, sizeof(buf), "fec0::%x:%x:%x:%x:%x:%x",
			host * 3, 17+host, host,
			host * 3, 17+host, host);
		if ((inaddr =__pmStringToSockAddr(buf)) == NULL) {
		  printf("insufficient memory\n");
		  continue;
		}
		sts = __pmAccAddClient(inaddr, &i);
		__pmSockAddrFree(inaddr);
		if (sts < 0) {
		    if (j == host && sts == PM_ERR_CONNLIMIT)
			continue;
		    printf("add IPv6 client from host %d (j=%d): %s\n",
			   j, host, pmErrStr(sts));
		    continue;
		}
		else if (i != (~(1 << host)))
		    printf("IPv6 host %d: __pmAccAddClient returns denyOpsResult 0x%x (expected 0x%x)\n",
			   host, i, ~(1 << host));
	    }
	}
    }

    putc('\n', stderr);

    putc('\n', stderr);
    __pmAccDumpHosts(stderr);

    putc('\n', stderr);

    return 0;
}
