No problem!

On Fri, 2008-02-22 at 12:59 -0600, William A. Rowe, Jr. wrote:
> Guy Ferraiolo wrote:
> > Folks
> > 
> > I think flood is highly useful once the random substitution feature is
> > added.  If we got that into the code base there might be greater use of
> > flood and I think that would be a good thing.  Also, I have some other
> > features planned but I don't want to have several patches outstanding at
> > once.
> > 
> > If no one cares about this how about just putting it in?  I've been
> > working with flood for some time and I do care.  Is there anything I can
> > do to get this going?
> 
> I like the thought, but a pointer back to your patch, please?
-- 
Guy Ferraiolo                                   mailto:[EMAIL PROTECTED]
Performance Measurement & Analysis              http://CNET.com
CNET                                            tel: 1.908.541.3739
1200 Route 22 East                              fax: 1.908.575.7474
Bridgewater, NJ 08807                           cel: 1.732.618.0250
diff --exclude-from=excludefile -urN flood-orig/config.h.in flood-patchbuild/config.h.in
--- flood-orig/config.h.in	2007-12-19 11:54:42.000000000 -0800
+++ flood-patchbuild/config.h.in	2007-12-19 12:32:12.000000000 -0800
@@ -53,6 +53,10 @@
 #define XML_FARM_USEFARMER_COUNT "count"
 #define XML_FARM_USEFARMER_DELAY "startdelay"
 #define XML_FARM_USEFARMER_START "startcount"
+#define XML_SUBST_LIST "subst_list"
+#define XML_SUBST_ENTRY "subst_entry"
+#define XML_SUBST_VAR "subst_var"
+#define XML_SUBST_FILE "subst_file"
 
 /* The delimiter (used above) between XML elements */
 #define XML_ELEM_DELIM "."
diff --exclude-from=excludefile -urN flood-orig/examples/flood.dtd flood-patchbuild/examples/flood.dtd
--- flood-orig/examples/flood.dtd	2007-12-19 11:54:42.000000000 -0800
+++ flood-patchbuild/examples/flood.dtd	2007-12-19 12:32:12.000000000 -0800
@@ -1,5 +1,3 @@
-<?xml version="1.0" ?>
-
 <!--
 
      This is a DTD for flood configuration files.
@@ -12,8 +10,7 @@
      is valid (in contrast to just "well-formed").
 
 -->
-
-<!ELEMENT flood (urllist+,profile+,farmer+,farm+,seed?)>
+<!ELEMENT flood (urllist+,profile+,farmer+,farm+,seed?,subst_list?)>
 
 <!-- urllist -->
 <!ELEMENT urllist (name,description?,baseurl?,(url|sequence)+)>
@@ -46,6 +43,15 @@
 <!ATTLIST sequence sequencename CDATA #REQUIRED>
 <!ATTLIST sequence sequencelist CDATA #REQUIRED>
 
+<!-- subst_list -->
+<!--
+<!ELEMENT subst_list (subst_entry|subst_seq)>
+<!ELEMENT subst_entry (subst_file, subst_var)>
+<!ELEMENT subst_file (#PCDATA)>
+<!ELEMENT subst_var (#PCDATA)>
+<!ELEMENT subst_seq (subst_list+)>
+
+-->
 <!-- profile -->
 
 <!ENTITY % profile.events "(profile_init?,get_next_url?,create_req?,postprocess?,loop_condition?,profile_destroy?)+">
diff --exclude-from=excludefile -urN flood-orig/examples/subprojects flood-patchbuild/examples/subprojects
--- flood-orig/examples/subprojects	1969-12-31 16:00:00.000000000 -0800
+++ flood-patchbuild/examples/subprojects	2007-12-19 12:32:12.000000000 -0800
@@ -0,0 +1,2 @@
+test/flood
+apreq
diff --exclude-from=excludefile -urN flood-orig/examples/subst-example.xml flood-patchbuild/examples/subst-example.xml
--- flood-orig/examples/subst-example.xml	1969-12-31 16:00:00.000000000 -0800
+++ flood-patchbuild/examples/subst-example.xml	2007-12-19 12:32:12.000000000 -0800
@@ -0,0 +1,29 @@
+<flood configversion="1">
+  <urllist><name>Test Hosts</name><description>A bunch of hosts we want to hit</description><url method="GET" requesttemplate="http://httpd.apache.org/${subproject}";>http://httpd.apache.org/${subproject}</url></urllist>
+  <farm>
+    <name>Bingo</name>
+    <usefarmer count="1">Joe</usefarmer>
+  </farm>
+  <subst_list>
+    <subst_entry>
+      <subst_file>./subprojects</subst_file>
+      <subst_var>subproject</subst_var>
+    </subst_entry>
+  </subst_list>
+  <profile>
+    <name>RoundRobinProfile</name>
+    <profiletype>round_robin</profiletype>
+    <description>A Test Round Robin Configuration</description>
+    <verify_resp>verify_200</verify_resp>
+    <socket>generic</socket>
+    <report>easy</report>
+    <useurllist>Test Hosts</useurllist>
+  </profile>
+  <seed>1</seed>
+  <farmer>
+    <name>Joe</name>
+    <useprofile>RoundRobinProfile</useprofile>
+    <time>23</time>
+  </farmer>
+  <test_description>lab split test 2</test_description>
+</flood>
diff --exclude-from=excludefile -urN flood-orig/flood_round_robin.c flood-patchbuild/flood_round_robin.c
--- flood-orig/flood_round_robin.c	2007-12-19 11:54:42.000000000 -0800
+++ flood-patchbuild/flood_round_robin.c	2007-12-19 12:32:12.000000000 -0800
@@ -55,6 +55,7 @@
 #include "config.h"
 #include "flood_net.h"
 #include "flood_round_robin.h"
+#include "flood_subst_file.h"
 #include "flood_profile.h"
 
 /* On FreeBSD, the return of regexec() is 0 or REG_NOMATCH, and REG_OK is undefined */
@@ -116,6 +117,9 @@
 
     apr_hash_t *state;
 
+    int subst_count;
+    subst_rec_t* subst_list;
+
     int current_round;
     int current_url;
 
@@ -128,6 +132,16 @@
     int size, matchsize;
     regex_t re;
     regmatch_t match[2];
+    subst_rec_t* subst_rec_p;
+    char* lookup_val;
+    char subst_buf[8096];
+    apr_pool_t *local_pool;
+
+    if (apr_pool_create(&local_pool, NULL) != APR_SUCCESS) {
+      apr_file_printf(local_stderr, "Failed apr_pool_create!\n");
+      exit(-1);
+    }
+         
          
     prev = template;
     returnValue = NULL;
@@ -171,6 +185,26 @@
             data = apr_hash_get(rp->state, cur+match[1].rm_so, matchsize);
         }
 
+        /* if there is no data, maybe it's a random string subst */
+        /* try to do the substition */
+	if (!data) {
+	  matchsize = match[1].rm_eo - match[1].rm_so;
+	  lookup_val = apr_pstrndup(local_pool, cur+match[1].rm_so, matchsize);
+
+	  memset(subst_buf, 0, sizeof(subst_buf));
+	  subst_rec_p = subst_file_get(lookup_val, rp->subst_list);
+	  subst_file_entry_get(&subst_rec_p->subst_file, 
+			       &subst_rec_p->fsize, subst_buf, 
+			       sizeof(subst_buf));
+
+	  if (!strlen(subst_buf)) {
+            apr_file_printf(local_stderr, 
+                            "substitution didn't return data!\n");
+            exit(-1);
+	  } 
+	  data = apr_pstrdup(rp->pool, subst_buf);
+	}
+
         /* If there is no data, place the original string back. */
         if (!data) {
             data = apr_psprintf(rp->pool, "${%s}", 
@@ -204,7 +238,10 @@
     else
         returnValue = apr_pstrcat(rp->pool, returnValue, cur, NULL);
 
+    subst_file_entry_unescape(returnValue, sizeof(returnValue));
+
     regfree(&re);
+    apr_pool_destroy(local_pool);
     return returnValue;
 }
 
@@ -715,9 +752,13 @@
     int i;
     struct apr_xml_elem *root_elem, *profile_elem,
            *urllist_elem, *count_elem, *useurllist_elem, *baseurl_elem,
+      *subst_list_elem, *subst_entry_elem, *subst_entry_child,
            *proxyurl_elem, *e;
     round_robin_profile_t *p;
     char *xml_profile, *xml_urllist, *urllist_name;
+    char *xml_subst_list, *subst_list_name;
+    subst_rec_t* subst_rec_p; 
+    int valid_substs = 0; 
 
     p = apr_pcalloc(pool, sizeof(round_robin_profile_t));
     p->pool = pool;
@@ -833,6 +874,79 @@
 
     /* Reset this back to 0. */
     p->current_url = 0;
+    /* now initialize the subst_list for random text substitution */    
+    /* get the subst_list from the config file */    
+    /* the subst_list has pairs or substitution variables and files */    
+    /* later on, in handle_param_string(), when a substitution variable */    
+    /* is found, it will be substituted with a randomly chosen line from */    
+    /* the subsitution file */    
+    /* there can be an arbitrary number of such pairs */    
+    /* the pairs scope is the entire configuration file */    
+    /* they are not specific to a profile, url or urllist */    
+    
+    xml_subst_list = apr_pstrdup(pool, XML_SUBST_LIST);    
+
+    if ((rv = retrieve_xml_elem_child(
+         &subst_list_elem, root_elem, XML_SUBST_LIST)) == APR_SUCCESS) {
+      /* count the subst_entries for this config file and allocate space */
+      p->subst_count = 0;      
+      p->subst_count += count_xml_elem_child(subst_list_elem, XML_SUBST_ENTRY);
+      p->subst_list = apr_pcalloc(p->pool, sizeof(subst_rec_t) * (p->subst_count + 1));
+
+      /* get the subst_list info and populate the data structures */
+      subst_rec_p = p->subst_list;      
+      for (e = subst_list_elem->first_child; e; e = e->next) {
+        if (strncasecmp(e->name, XML_SUBST_ENTRY, FLOOD_STRLEN_MAX) == 0) {
+          subst_entry_elem = e;
+          for (subst_entry_child = subst_entry_elem->first_child; 
+                                   subst_entry_child; 
+                                   subst_entry_child = subst_entry_child->next) {
+            if (strncasecmp(subst_entry_child->name, 
+                            XML_SUBST_VAR, FLOOD_STRLEN_MAX) == 0) {
+              if (subst_entry_child->first_cdata.first 
+                  && subst_entry_child->first_cdata.first->text) {
+                (subst_rec_t*)subst_rec_p->subst_var = 
+                    apr_pstrdup(pool, 
+                                subst_entry_child->first_cdata.first->text);
+              }
+            }
+
+            if (strncasecmp(subst_entry_child->name, 
+                            XML_SUBST_FILE, FLOOD_STRLEN_MAX) == 0) {
+              if (subst_entry_child->first_cdata.first 
+                  && subst_entry_child->first_cdata.first->text) {
+                (subst_rec_t*)subst_rec_p->subst_file_name = 
+                    apr_pstrdup(pool, 
+                                subst_entry_child->first_cdata.first->text);
+              }
+            }
+          }
+        }
+        /* this is the end of each subst_entry fetch */
+        /* at this point we should have the subst_var and subst_file_name */
+        if (subst_rec_p->subst_var && subst_rec_p->subst_file_name) {
+          subst_rec_p->valid = 1;
+        }
+        /* we should have the same number of valid substs as */
+        /* the subst_count above */
+        valid_substs++;
+        subst_rec_p++;
+      }
+      if (valid_substs != p->subst_count) {
+          apr_file_printf(local_stderr,
+          "Profile '%s' valid substs: %d inconsistent with subst count %d.\n",
+          profile_name, valid_substs, p->subst_count);
+        return APR_EGENERAL;
+      }
+      /* now open all the substitution files */
+      subst_rec_p = p->subst_list;
+      while(subst_rec_p->valid) {
+        subst_file_open(&(subst_rec_p->subst_file), 
+                        subst_rec_p->subst_file_name, 
+                        &(subst_rec_p->fsize), pool);
+        subst_rec_p++;
+      }
+    }
 
     *profile = p;
 
diff --exclude-from=excludefile -urN flood-orig/flood_subst_file.c flood-patchbuild/flood_subst_file.c
--- flood-orig/flood_subst_file.c	1969-12-31 16:00:00.000000000 -0800
+++ flood-patchbuild/flood_subst_file.c	2007-12-19 12:32:12.000000000 -0800
@@ -0,0 +1,245 @@
+#include <assert.h>
+#include <apr_general.h>
+#include <apr_file_io.h>
+#include "flood_subst_file.h"
+#define IS_NUM(c)       (('0' <= (c)) && ('9' >= (c)))
+
+apr_file_t* subst_file = NULL;
+extern apr_file_t *local_stdout;
+extern apr_file_t *local_stderr;
+apr_off_t fsize;
+char * pp = "thisis\nmytest";
+
+void subst_list_init(subst_rec_t *subst_list, int subst_list_size) {
+  int i;
+
+  for (i = 0; i < SUBST_FILE_ARR_MAX; i++) {
+    subst_list[i].subst_var = NULL;
+    subst_list[i].subst_file_name = NULL;
+    subst_list[i].subst_mode = 0;
+    subst_list[i].fsize = (apr_off_t)0;
+    subst_list[i].valid = 0;
+    subst_list[i].subst_file = NULL;
+  }
+}
+
+void subst_list_make(subst_rec_t *subst_list) {
+  int i2 = 0;
+
+  subst_list[0].subst_var = "name";
+  subst_list[0].subst_file_name = "/pmalab1/temphome/guyf/work/replace_mc5/flood_stuff/build/flood-0.4/test";
+  subst_list[0].subst_mode = 0;
+  subst_list[0].valid = 1;
+  i2++;
+
+  subst_list[i2].subst_var = "foot";
+  subst_list[i2].subst_file_name = "/pmalab1/temphome/guyf/work/replace_mc5/flood_stuff/build/flood-0.4/blort";
+  subst_list[i2].subst_mode = 0;
+  subst_list[i2].valid = 1;
+
+  i2++;
+  subst_list[i2].subst_var = "nerve";
+  subst_list[i2].subst_file_name = "/pmalab1/temphome/guyf/work/replace_mc5/flood_stuff/build/flood-0.4/cavort";
+  subst_list[i2].subst_mode = 0;
+  subst_list[i2].valid = 1;
+}
+
+subst_rec_t* subst_file_get(const char* varname, subst_rec_t* subst_list) {
+  int i;
+
+  for (i = 0; i < SUBST_FILE_ARR_MAX; i++) {
+    if ((strcmp(subst_list[i].subst_var, varname) == 0)
+	&& subst_list[i].valid) {
+      return &(subst_list[i]);
+    }
+  }
+  return NULL;
+}
+
+
+void subst_file_err(const char* msgtext, const char* vartext, apr_status_t errcode) {
+  char errtext[SUBST_FILE_ERROR_BUF];
+  apr_file_t* local_stderr;
+  apr_pool_t *err_pool;
+
+  if (apr_pool_create(&err_pool, NULL) != APR_SUCCESS) {
+    printf("Failed apr_pool_create\n");
+    exit(-1);
+  }
+
+  apr_strerror(errcode, (char *) &errtext, SUBST_FILE_ERROR_BUF);
+  apr_file_open_stderr(&local_stderr, err_pool);
+
+  apr_file_printf(local_stderr, "%s %s %s\n", msgtext, vartext, errtext);
+  apr_file_close(local_stderr);
+
+  apr_pool_destroy(err_pool);
+}
+
+
+int subst_file_open(apr_file_t** subst_file, const char* fname, apr_off_t* fsize, apr_pool_t* pool) {
+  apr_finfo_t finfo;
+  apr_status_t rc = 0;
+  apr_int32_t wanted = APR_FINFO_SIZE;
+
+  rc  = apr_file_open(subst_file, fname, APR_READ, APR_OS_DEFAULT, pool);
+
+  if (rc) {
+    subst_file_err("Couldn't open file", fname, rc);
+    exit(-1 );
+  }
+
+  rc = 0;
+  if (rc = apr_stat(&finfo, fname, wanted, pool)) {
+    subst_file_err("stat failed on file ", fname, rc);
+    apr_file_close(*subst_file);
+    exit(-1);
+  }
+  *fsize = finfo.size;
+
+  return 0;
+}
+
+
+int close_subst_file(apr_file_t* subst_file) {
+  apr_status_t rc = 0;
+
+  if (subst_file) {
+    rc = apr_file_close(subst_file);
+  }
+  return rc;
+}
+
+ 
+char* subst_file_entry_get(apr_file_t** subst_file, apr_off_t *fsize, char* line, int line_size) {
+  apr_off_t seek_val;
+  apr_off_t zero = 0;
+  apr_status_t rc = 0;
+
+  if (!subst_file ) {
+    subst_file_err("subst_file not open ", "", rc);
+    exit(-1);
+  }
+  assert (line_size > 0);
+  assert (*fsize > 0);
+  seek_val = random() % *fsize;
+
+  if (apr_file_seek(*subst_file, APR_SET, &seek_val) != 0 )  {
+    subst_file_err("error in seeking for file", "no name available", rc);    
+    exit(-1 );
+  }
+
+  apr_file_gets(line, line_size, *subst_file);
+  memset(line, 0, line_size);
+  if (apr_file_gets(line, line_size, *subst_file) != (apr_status_t)0 ) {
+    if (apr_file_seek(*subst_file, APR_SET, &zero) != (apr_off_t)0 )  {
+      subst_file_err("error in seeking for file", "no name available", rc);    
+      exit(-1 );
+    }
+    apr_file_gets(line, line_size, *subst_file);
+  }
+  line[strlen(line)-1] = '\0';
+  return line;
+}
+
+
+/* a substitution file entry (nomimally a single line) can now contain */
+/* escaped characters such as \n, \t, \012 so that the entry can be */
+/* a multi-line POST payload */
+char* subst_file_entry_unescape(char* line, int line_size)
+{
+  int num;
+  char *from, *to;
+  char changed_buf[SUBST_FILE_MAX_URL_SIZE];
+ 
+ if (line == NULL) {
+    return NULL;
+  }
+
+  from = to = line;
+  while (*from) {
+    if (*from == '\\') {
+      ++from;
+      if (IS_NUM(*from)) {
+	num = *from++ - '0';
+	if (IS_NUM(*from))
+	  num = num*10 + (*from++ - '0');
+	if (IS_NUM(*from))
+	  num = num*10 + (*from++ - '0');
+	if (num != 0) {
+	  *to++ = num;
+	} else {
+	  *to++ = '\\';
+	  *to++ = '0';
+	}
+      } else {
+	switch (*from) {
+	case '\0': continue;
+	case 'n': *to++ = '\n'; break;
+	case 'r': *to++ = '\r'; break;
+	case 't': *to++ = '\t'; break;
+	default: *to++ = *from; break;
+	}
+	++from;
+      }
+    } else {
+      *to++ = *from++;
+    }
+  }
+  *to = '\0';
+
+  return line;
+}
+
+#ifdef SUBST_MAIN
+int main(int argc, char** argv) {
+  char line[SUBST_FILE_MAX_URL_SIZE];    # why mess around, therefore static
+  int i = 20;
+  int list = 0;
+  char* the_name;
+  subst_rec_t *the_rec;
+
+  apr_initialize();
+  atexit(apr_terminate);
+
+  if (apr_pool_create(&pool, NULL) != APR_SUCCESS) {
+    printf("Failed apr_pool_create\n");
+    exit(-1);
+  }
+
+  srandom(time(NULL));
+
+  subst_list_init(subst_list, SUBST_FILE_ARR_MAX);
+  subst_list_make(subst_list);
+
+  while(subst_list[list].valid && list < 10) {
+    subst_file_open(&(subst_list[list].subst_file), subst_list[list].subst_file_name, &(subst_list[list].fsize));
+    list++;
+  }
+
+/*   list = 0; */
+/*   while (i--) { */
+/*     while(subst_list[list].valid && list < 10) { */
+/*       subst_file_entry_get(&(subst_list[list].subst_file), &(subst_list[list].fsize), line, sizeof(line)); */
+/*       printf("%s\n", line); */
+/*       memset(line, 0, sizeof(line));       */
+/*       list++; */
+/*     } */
+/*     list = 0; */
+/*   } */
+
+  the_name = "test";
+  the_rec = subst_file_get(the_name, subst_list);
+  subst_file_entry_get(&(the_rec->subst_file), &(the_rec->fsize), line, sizeof(line));
+  printf("%s\n", line);
+
+  list = 0;
+  while(subst_list[list].valid && list < 10) {
+    close_subst_file(subst_list[list].subst_file);
+    list++;
+  }
+
+  exit(0);
+}
+
+#endif
diff --exclude-from=excludefile -urN flood-orig/flood_subst_file.h flood-patchbuild/flood_subst_file.h
--- flood-orig/flood_subst_file.h	1969-12-31 16:00:00.000000000 -0800
+++ flood-patchbuild/flood_subst_file.h	2007-12-19 12:32:12.000000000 -0800
@@ -0,0 +1,25 @@
+#ifndef _SUBST_FILE_H
+#define _SUBST_FILE_H 1
+
+#define SUBST_FILE_MAX_URL_SIZE 8096
+#define SUBST_FILE_ERROR_BUF 256
+#define SUBST_FILE_ARR_MAX 10
+struct subst_rec_t {
+  char* subst_var;
+  char* subst_file_name;
+  apr_file_t* subst_file;
+  int subst_mode;
+  apr_off_t fsize;
+  int valid;
+};
+typedef struct subst_rec_t subst_rec_t;
+subst_rec_t subst_list[SUBST_FILE_ARR_MAX];
+//int subst_list_size = sizeof(subst_list)/sizeof(subst_rec_t);
+
+void subst_file_err(const char*, const char*, apr_status_t);
+int subst_file_open(apr_file_t**, const char*, apr_off_t*, apr_pool_t*);
+int close_subst_file(apr_file_t*);
+char* subst_file_entry_get(apr_file_t**, apr_off_t*, char*, int);
+subst_rec_t* subst_file_get(const char*, subst_rec_t*);
+
+#endif
diff --exclude-from=excludefile -urN flood-orig/Makefile.in flood-patchbuild/Makefile.in
--- flood-orig/Makefile.in	2007-12-19 11:54:42.000000000 -0800
+++ flood-patchbuild/Makefile.in	2007-12-19 12:32:12.000000000 -0800
@@ -26,7 +26,7 @@
 	flood_farmer.lo flood_simple_reports.lo flood_easy_reports.lo \
 	flood_farm.lo \
 	flood_socket_generic.lo flood_socket_keepalive.lo \
-	flood_report_relative_times.lo
+	flood_report_relative_times.lo flood_subst_file.lo
 
 flood_OBJECTS = flood.lo $(FLOOD_OBJS)
 flood: $(flood_OBJECTS) $(PROGRAM_DEPENDENCIES)

Reply via email to