Commit 3a330862 authored by John DuBois's avatar John DuBois

[1324]

Rewrote command line processing interface to conform to requirements.
Rewrote gtests for new interface.
Completed changes for BIND9 coding guidelines.
parent d85912df
......@@ -18,8 +18,20 @@
#include "procconf.h"
#include "perfdhcp.h"
#include "cloptions.h"
#include "dkdebug.h"
static void printHelp(const char* progName, const char* usage);
static void initialize(void);
static int v6 = 0; // DHCPv6 operation (-6)
static int initialOnly = 0; // Do only initial exchange (-i)
static unsigned rate = 0; // Request rate (-r)
static unsigned numRequest = 0; // Number of requests (-n)
static double dropTime = 0.0; // Response timeout (-d)
static double testPeriod = 0.0; // Test period (-p)
static const char* server; // Server to contact
static const char* maxDropOpt = NULL; // Max dropped responses (-D)
static const char* localName = NULL; // Local host/interface (-l)
/*
* Return value:
......@@ -28,54 +40,69 @@ static void printHelp(const char* progName, const char* usage);
* 1 if argument processing was successful and the program should continue.
*/
int
procArgs(int argc, const char* argv[], confdata_t* confdata,
const char** server) {
procArgs(int argc, const char* argv[]) {
char usage[] =
"Usage:\n\
perfdhcp [-hv] [-4|-6] [-r<rate>] [-n<num-request>] [-p<test-period>]\n\
[-d<drop-time>] [-D<max-drop>] [-l<local-addr|interface>] [-i]\n\
[-x<diagnostic-selector>] [server]\n";
int v4 = 0;
int v6 = 0;
const char* localName = NULL;
const char* msg;
char* maxDropOpt;
double dropTime;
double testPeriod;
int v4 = 0; /* DHCPv4 operation explicitly requested */
const char* msg; /* Failure message from procOpts() */
int help = 0; /* Help requested */
int version = 0; /* Version requested */
const char* diagStr = NULL; /* Diagnostics requested (-x) */
/* Names of configuration variables, for defaults file processor */
/* option descriptions */
confvar_t optConf[] = {
{ 'h', NULL, CF_SWITCH, NULL, 0 },
{ 'v', NULL, CF_SWITCH, NULL, 0 },
{ '4', NULL, CF_SWITCH, &v4, 1 },
{ '6', NULL, CF_SWITCH, &v6, 1 },
{ 'i', NULL, CF_SWITCH, NULL, 1 },
{ 'l', NULL, CF_NE_STRING, &localName, 0 },
{ 'r', NULL, CF_POS_INT, NULL, 0 },
{ 'x', NULL, CF_STRING, NULL, 0 },
{ 'd', NULL, CF_POS_FLOAT, &dropTime, 0 },
{ 'D', NULL, CF_NE_STRING, &maxDropOpt, 0 },
{ 'n', NULL, CF_POS_INT, NULL, 0 },
{ 'p', NULL, CF_POS_FLOAT, &testPeriod, 0 },
{ '\0', NULL, CF_ENDLIST, NULL, 0 }
{ 'h', NULL, CF_SWITCH, &help, 1 },
{ 'v', NULL, CF_SWITCH, &version, 1 },
{ '4', NULL, CF_SWITCH, &v4, 1 },
{ '6', NULL, CF_SWITCH, &v6, 1 },
{ 'i', NULL, CF_SWITCH, &initialOnly, 1 },
{ 'l', NULL, CF_NE_STRING, &localName, 0 },
{ 'r', NULL, CF_POS_INT, &rate, 0 },
{ 'n', NULL, CF_POS_INT, &numRequest, 0 },
{ 'd', NULL, CF_POS_FLOAT, &dropTime, 0 },
{ 'p', NULL, CF_POS_FLOAT, &testPeriod, 0 },
{ 'D', NULL, CF_NE_STRING, &maxDropOpt, 0 },
{ 'x', NULL, CF_STRING, &diagStr, 0 },
{ '\0', NULL, CF_ENDLIST, NULL, 0 }
};
/* diagnostic map */
const struct dkdesc diagLetters[] = {
{ 's', DK_SOCK },
{ 'm', DK_MSG },
{ 'p', DK_PACKET },
{ 'a', DK_ALL },
{ '\0', 0 }
};
/* Process command line options and config file */
msg = procOpts(&argc, &argv, optConf, confdata, progName, NULL);
initialize();
/* Process command line options */
msg = procOpts(&argc, &argv, optConf, NULL, progName, NULL);
if (msg != NULL) {
fprintf(stderr, "%s: %s\n", progName, msg);
return(2);
}
if (confdata->map['h']->num > 0) {
if (help) {
printHelp(progName, usage);
return(0);
}
if (confdata->map['v']->num > 0) {
if (version) {
printf("dhcpperf v1.0 2011-10-30\n");
return(0);
}
if (diagStr != NULL) {
char c;
if ((c = dk_setup(diagStr, diagLetters)) != '\0') {
fprintf(stderr,
"%s: Invalid selector character given with -x: '%c'\n",
progName, c);
return(2);
}
}
if (v4 && v6) {
fprintf(stderr, "%s: Must not give -4 and -6 together.\n", progName);
......@@ -84,7 +111,7 @@ perfdhcp [-hv] [-4|-6] [-r<rate>] [-n<num-request>] [-p<test-period>]\n\
switch (argc) {
case 0:
if (v6 && localName != NULL) {
*server = "all";
server = "all";
} else {
if (v6) {
fprintf(stderr,
......@@ -99,7 +126,7 @@ perfdhcp [-hv] [-4|-6] [-r<rate>] [-n<num-request>] [-p<test-period>]\n\
}
break;
case 1:
*server = argv[0];
server = argv[0];
break;
default:
fprintf(stderr, "%s: Too many arguments.\n\%s\n", progName, usage);
......@@ -108,6 +135,22 @@ perfdhcp [-hv] [-4|-6] [-r<rate>] [-n<num-request>] [-p<test-period>]\n\
return(1);
}
/*
* Initialize values set by procArgs().
* Initialized though they are static to allow for repeated calls for testing.
*/
static void
initialize(void) {
v6 = 0;
initialOnly = 0;
rate = 0;
numRequest = 0;
dropTime = 0.0;
testPeriod = 0.0;
maxDropOpt = NULL;
localName = NULL;
}
static void
printHelp(const char* progName, const char* usage) {
printf(
......@@ -152,8 +195,8 @@ Options:\n\
generated.\n\
-v: Report the version number of this program.\n\
-x<diagnostic-selector>: Include extended diagnostics in the output.\n\
<diagnostic-selector> is a string of single-keywords specifying the\n\
operations for which verbose output is desired. The selector keyletters\n\
<diagnostic-selector> is a string of characters, each specifying an\n\
operation for which verbose output is desired. The selector characters\n\
are:\n\
[TO BE ADDED]\n\
\n\
......@@ -185,3 +228,48 @@ The exit status is:\n\
are not successfully completed.\n",
progName, usage);
}
int
getv6(void) {
return v6;
}
int
getinitialOnly(void) {
return initialOnly;
}
unsigned
getrate(void) {
return rate;
}
unsigned
getnumRequest(void) {
return numRequest;
}
double
getdropTime(void) {
return dropTime;
}
double
gettestPeriod(void) {
return testPeriod;
}
const char *
getserver(void) {
return server;
}
const char *
getlocalName(void) {
return localName;
}
const char *
getmaxDrop(void) {
return maxDropOpt;
}
......@@ -26,17 +26,24 @@
* Input varibles:
* argc, argv: Command line data.
*
* Output variables:
* confdata; Processed command line data.
* server: The server to contact. This will always be set, either to the given
* value or to "all" (see usage).
*
* Return value:
* 0 if the command has been satisfied and the program should exit 0.
* 2 for usage error, in which case an error message will have been printed.
* 1 if argument processing was successful and the program should continue.
*/
int procArgs(int argc, const char* argv[], confdata_t* confdata,
const char** server);
int procArgs(int argc, const char* argv[]);
/*
* These functions return values set by command line options
*/
int getv6(void); // DHCPv6 operation (-6)
int getinitialOnly(void); // Do only initial exchange (-i)
unsigned getrate(void); // Request rate (-r)
unsigned getnumRequest(void); // Number of requests (-n)
double getdropTime(void); // Response timeout (-d)
double gettestPeriod(void); // Test period (-p)
const char* getserver(void); // Server to contact
const char* getlocalName(void); // Local host/interface (-l)
const char* getmaxDrop(void); // Max dropped responses (-D)
#endif
......@@ -20,22 +20,23 @@
unsigned dk_diag_mask;
int
char
dk_setup(const char* diag_str, const struct dkdesc* diags) {
dk_diag_mask = 0;
int i;
for (; *diag_str != '\0'; diag_str++)
for (; *diag_str != '\0'; diag_str++) {
for (i = 0; diags[i].keyletter != '\0'; i++) {
if (diags[i].keyletter == *diag_str) {
dk_diag_mask |= diags[i].mask;
break;
}
if (diags[i].keyletter == '\0') {
return(0);
}
}
return(1);
if (diags[i].keyletter == '\0') {
return(*diag_str);
}
}
return('\0');
}
void
......@@ -56,5 +57,5 @@ vdkprintf(unsigned diag_req, const char format[], va_list ap) {
int
dk_set(unsigned diag_req) {
return(diag_req & dk_diag_mask);
return((diag_req & dk_diag_mask) != 0);
}
......@@ -14,6 +14,13 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
* This module implements a mask-style diagnostic printing/selection system.
* Each diagnostic is enabled by including an associated keyletter in a
* selector string given at initialization time (typically as a command-line
* option).
*/
#ifndef DKDEBUG_H
#define DKDEBUG_H
......@@ -23,16 +30,56 @@ extern "C" {
#include <stdarg.h>
/* Use as the mask in a dkdesc structure to enable all diagnostics */
#define DK_ALL (~0)
/*
* Elements of this type are used to map the available diagnostic keyletters to
* mask bits.
*/
struct dkdesc {
char keyletter;
unsigned mask;
};
/*
* Initialize diagnostic mask.
*
* Input variables:
*
* diag_str is a string giving the keyletters for diagnostics to enable.
*
* diags describes the available diagnostics, mapping each keyletter to any
* number of mask bits. It should be terminated with an element with keyletter
* set to the null character.
*
* Return value:
* If an invalid character is given in diag_str, that character; otherwise a
* null character.
*/
char dk_setup(const char* diag_str, const struct dkdesc* diags);
/*
* The remaining functions test the mask bitset diag_req against the currently
* enabled diagnostics, as set by dk_setup(). If any bits set in diag_req are
* among the enabled diagnostics, the diagnostic operation is enabled.
*/
/*
* If diagnostic operation is enabled, use the remaining arguments to print
* like fprintf(stderr, )
*/
void dkprintf(unsigned diag_req, const char format[], ...);
/*
* If diagnostic operation is enabled, use the remaining arguments to print
* like vfprintf(stderr, )
*/
void vdkprintf(unsigned diag_req, const char format[], va_list ap);
int dk_setup(const char* diag_str, const struct dkdesc* diags);
/*
* If diagnostic operation is enabled, return 1; else return false.
*/
int dk_set(unsigned diag_req);
#ifdef __cplusplus
......
......@@ -21,6 +21,10 @@
extern "C" {
#endif
#define DK_SOCK 1
#define DK_MSG 2
#define DK_PACKET 4
const char progName[] = "dhcpperf";
#ifdef __cplusplus
......
......@@ -106,7 +106,8 @@ opterror(const char* expected, const char* value, const confvar_t* varDesc,
* varDesc is the description structure for this option.
*
* Output variables:
* The option value is stored in the option list pointed to by first.
* The option data is stored in a malloced confval structure, which is appended
* to the option list pointed to by first. The 'next' element is set to NULL.
* last is used to track the last record in each option list, so option values
* can be appended easily.
*
......@@ -136,7 +137,7 @@ addOptVal(const char* value, const confvar_t* varDesc,
}
data.value.charval = *value;
if (addr != NULL) {
*(char*) addr = *value;
*(char*)addr = *value;
}
break;
case CF_STRING:
......@@ -147,7 +148,7 @@ addOptVal(const char* value, const confvar_t* varDesc,
}
data.value.string = value;
if (addr != NULL) {
*(const char**) addr = value;
*(const char**)addr = value;
}
break;
case CF_INT:
......@@ -189,7 +190,7 @@ addOptVal(const char* value, const confvar_t* varDesc,
;
}
if (addr != NULL) {
*(int*) addr = data.value.intval;
*(int*)addr = data.value.intval;
}
break;
case CF_FLOAT:
......@@ -228,14 +229,14 @@ addOptVal(const char* value, const confvar_t* varDesc,
;
}
if (addr != NULL) {
*(double*) addr = data.value.floatval;
*(double*)addr = data.value.floatval;
}
break;
case CF_SWITCH:
data.value.switchval = varDesc->value;
value = "1"; /* for debugging */
if (addr != NULL) {
*(int*) addr = varDesc->value;
*(int*)addr = varDesc->value;
}
break;
case CF_ENDLIST:
......@@ -282,7 +283,7 @@ procCmdLineArgs(int* argc, const char** argv[], const confvar_t optConf[],
char optstr[514]; /* List of option chars, for getopt */
unsigned optCharToConf[256]; /* Map option char/num to confvar */
int optchar; /* value returned by getopt() */
unsigned confNum; /* to iterate over confvars */
int confNum; /* to iterate over confvars */
int count = 0; /* number of options processed */
p = optstr;
......@@ -290,7 +291,7 @@ procCmdLineArgs(int* argc, const char** argv[], const confvar_t optConf[],
for (confNum = 0; optConf[confNum].type != CF_ENDLIST; confNum++) {
unsigned outind = optConf[confNum].outind;
if (outind < 256 && isprint(outind)) {
*(p++) = (char) outind;
*(p++) = (char)outind;
switch (optConf[confNum].type) {
case CF_SWITCH:
break;
......@@ -304,7 +305,8 @@ procCmdLineArgs(int* argc, const char** argv[], const confvar_t optConf[],
*p = '\0';
optind = 1;
while ((optchar = getopt(*argc, const_cast<char**>(*argv), optstr)) != -1) {
while ((optchar = getopt(*argc, const_cast<char**>(*argv), optstr)) != -1)
{
int ind;
int ret;
......@@ -341,15 +343,23 @@ procCmdLineArgs(int* argc, const char** argv[], const confvar_t optConf[],
* and the program exits.
*
* Output variables:
* The processed option values are stored in confdata.
* Option values are stored at the value given by any confvar that has a
* non-null address.
* If confdatda is not null, the processed option values are stored in
* confdata.
* A pointer to the start of the values for each option is stored in
* confdata->optVals[].values at the same offset as the option appears in
* confdata[].
* For any option for option characters/indexes have been used,
* For any option for option characters/indexes that have been used,
* confdata->map[index] is set to the same data.
* After processing, argc will have been adjusted to be the number of
* non-option arguments and argv will have been adjusted to start with the
* first non-option argument.
* The malloced data structures returned in confdata are:
* optVals
* optVals[0].values
* If any option characters/indexes are used, map. If not used, this will be
* a null pointer.
*
* Return value:
* On success, NULL.
......@@ -366,8 +376,8 @@ procOpts(int* argc, const char** argv[], const confvar_t optConf[],
unsigned maxOptIndex = 0; /* The highest option index number seen */
/* number of option instances + assignments given */
int numOptsFound;
unsigned optNum; /* to iterate through the possible options */
unsigned i; /* index into the global list of option value structures */
int optNum; /* to iterate through the possible options */
int i; /* index into the global list of option value structures */
confval** valuePointers; /* global list of value structures */
pc_name = name;
......@@ -379,6 +389,10 @@ procOpts(int* argc, const char** argv[], const confvar_t optConf[],
maxOptIndex = outind & ~CF_NOTFLAG;
}
}
if (numConf == 0) {
error(INTERNAL_ERROR, "Empty confvar list");
return(errmsg);
}
if ((first = (confval**)pc_malloc(sizeof(confval*) * numConf)) == NULL ||
(last =
(confval**)pc_malloc(sizeof(confval*) * numConf)) == NULL) {
......@@ -387,28 +401,36 @@ procOpts(int* argc, const char** argv[], const confvar_t optConf[],
memset(first, '\0', sizeof(confval*) * numConf);
memset(last, '\0', sizeof(confval*) * numConf);
if ((numOptsFound =
procCmdLineArgs(argc, argv, optConf, first, last)) < 0) {
numOptsFound = procCmdLineArgs(argc, argv, optConf, first, last);
free(last);
last = NULL;
if (numOptsFound < 0)
{
free(first);
return(errmsg);
}
free(last);
if (confdata == NULL) {
free(first);
return NULL;
}
/*
* All options have been read & initial processing done.
* An array of pointers is now generated for the options.
*/
if ((valuePointers =
(confval**)pc_malloc(sizeof(confval*) * numOptsFound)) == NULL ||
(confval**)pc_malloc(sizeof(confval*) * numOptsFound)) == NULL ||
(confdata->optVals =
(cf_option*)pc_malloc(sizeof(cf_option) * numConf)) == NULL) {
(cf_option*)pc_malloc(sizeof(cf_option) * numConf)) == NULL) {
return(errmsg);
}
/* If option index numbers are used, allocate a map for them */
if (maxOptIndex != 0) {
if ((confdata->map =
(cf_option**)pc_malloc(sizeof(cf_option) * (maxOptIndex+1)))
== NULL) {
/* If option characters / indexes are used, allocate a map for them */
if (maxOptIndex == 0) {
confdata->map = NULL;
} else {
if ((confdata->map = (cf_option**)pc_malloc(sizeof(cf_option) *
(maxOptIndex+1))) == NULL) {
return(errmsg);
}
memset(confdata->map, '\0', sizeof(confval*) * (maxOptIndex+1));
......@@ -437,3 +459,17 @@ procOpts(int* argc, const char** argv[], const confvar_t optConf[],
free(first);
return(NULL);
}
/*
* Free the malloced data stored in confdata elements by ProcOpts()
*/
void
confdataFree(confdata_t *confdata) {
if (confdata->map != NULL) {
free(confdata->map);
confdata->map = NULL;
}
free(confdata->optVals[0].values);
free(confdata->optVals);
confdata->optVals = NULL;
}
......@@ -120,4 +120,9 @@ procOpts(int* argc, const char** argv[], const confvar_t optConf[],
confdata_t* confdata, const char name[],
const char usage[]);
/*
* Free the malloced data stored in confdata elements by ProcOpts()
*/
void confdataFree(confdata_t *confdata);
#endif
......@@ -3,6 +3,7 @@ SUBDIRS = .
AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
AM_CPPFLAGS += $(BOOST_INCLUDES)
AM_CXXFLAGS = $(B10_CXXFLAGS)
AM_CXXFLAGS += -g
if USE_STATIC_LINK
AM_LDFLAGS = -static
......@@ -17,6 +18,7 @@ run_unittests_SOURCES = run_unittests.cc
run_unittests_SOURCES += cloptions_unittest.cc
run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/cloptions.cc
run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/procconf.cc
run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/dkdebug.cc
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
......
......@@ -18,13 +18,14 @@
#include <stdarg.h>
#include "../cloptions.h"
#include "../perfdhcp.h"
#include "../dkdebug.h"
// Up to 4 arguments may be specified
// The final argument must be NULL. This is not counted in the 4 arguments.
int checkOption(confdata_t* confdata, int retExpected, ...) {
int checkOption(int retExpected, ...) {
const char* argv[6] = { "perfdhcp" };
int argc = 1;
const char* server;
int ret;
const char* p;
va_list ap;
......@@ -37,30 +38,23 @@ int checkOption(confdata_t* confdata, int retExpected, ...) {
}
va_end(ap);
argv[argc++] = "foo"; /* server */
ret = procArgs(argc, argv, confdata, &server);
ret = procArgs(argc, argv);
EXPECT_EQ(ret, retExpected);
return(ret == retExpected);
}
void checkOptionInvalid(const char* optflag, const char* optval) {
confdata_t confdata;
checkOption(&confdata, 2, optflag, optval, NULL);
checkOption(2, optflag, optval, NULL);
}
int checkOptionValid(const char* optflag, const char* optval,
confdata_t* confdata) {
int checkOptionValid(const char* optflag, const char* optval) {
return(checkOption(confdata, 1, optflag, optval, NULL));
return(checkOption(1, optflag, optval, NULL));
}
void checkPosFloatOpt(const char* optflag) {
confdata_t confdata;
if (checkOptionValid(optflag, "100.0", &confdata)) {
EXPECT_EQ(100.0,
confdata.map[(unsigned)optflag[1]]->values[0]->
value.floatval);
void checkPosFloatOpt(const char* optflag, double (*retfunc)(void)) {
if (checkOptionValid(optflag, "100.0")) {
EXPECT_EQ(100.0, (*retfunc)());
}
checkOptionInvalid(optflag, "0");
checkOptionInvalid(optflag, "-1");
......@@ -69,12 +63,9 @@ void checkPosFloatOpt(const char* optflag) {
checkOptionInvalid(optflag, "x");