MEDIUM: sample: add trie support to 51Degrees
Trie or pattern algorithm is used depending on what 51Degrees source
files are provided to MAKE.
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 44b1c2c..30d51c7 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -1752,7 +1752,7 @@
#ifdef USE_51DEGREES
else if (strcmp(args[0], "51degrees-data-file") == 0) {
if(!*(args[1])) {
- Alert("parsing [%s:%d]: '%s' expects a filepath to a 51Degrees data file.\n", file, linenum, args[0]);
+ Alert("parsing [%s:%d]: '%s' expects a filepath to a 51Degrees trie or pattern data file.\n", file, linenum, args[0]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
@@ -1760,12 +1760,12 @@
}
else if (strcmp(args[0], "51degrees-property-seperator") == 0) {
if(!*(args[1])) {
- Alert("parsing [%s:%d]: '%s' expects a ingle character.\n", file, linenum, args[0]);
+ Alert("parsing [%s:%d]: '%s' expects a single character.\n", file, linenum, args[0]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
if (strlen(args[1]) > 1) {
- Alert("parsing [%s:%d]: '%s' expects a ingle character, got '%s'.\n", file, linenum, args[0], args[1]);
+ Alert("parsing [%s:%d]: '%s' expects a single character, got '%s'.\n", file, linenum, args[0], args[1]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
diff --git a/src/haproxy.c b/src/haproxy.c
index daf68d0..e04aa3f 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -548,8 +548,8 @@
#ifdef USE_51DEGREES
int i = 0;
struct _51d_property_names *name;
- fiftyoneDegreesDataSetInitStatus _51d_dataset_status;
char **_51d_property_list;
+ fiftyoneDegreesDataSetInitStatus _51d_dataset_status = DATA_SET_INIT_STATUS_NOT_SET;
#endif
chunk_init(&trash, malloc(global.tune.bufsize), global.tune.bufsize);
@@ -1108,9 +1108,14 @@
list_for_each_entry(name, &global._51d_property_names, list)
_51d_property_list[i++] = name->name;
+#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
+ _51d_dataset_status = fiftyoneDegreesInitWithPropertyArray(global._51d_data_file_path, _51d_property_list, i);
+#endif
+#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
_51d_dataset_status = fiftyoneDegreesInitWithPropertyArray(global._51d_data_file_path, &global._51d_data_set, _51d_property_list, i);
- free(_51d_property_list);
+#endif
chunk_reset(&trash);
+
switch (_51d_dataset_status) {
case DATA_SET_INIT_STATUS_SUCCESS:
break;
@@ -1118,23 +1123,37 @@
chunk_printf(&trash, "Insufficient memory.");
break;
case DATA_SET_INIT_STATUS_CORRUPT_DATA:
- chunk_printf(&trash, "Corrupt data.");
+#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
+ chunk_printf(&trash, "Corrupt data file. Check that the data file provided is uncompressed and Trie data format.");
+#endif
+#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
+ chunk_printf(&trash, "Corrupt data file. Check that the data file provided is uncompressed and Pattern data format.");
+#endif
break;
case DATA_SET_INIT_STATUS_INCORRECT_VERSION:
- chunk_printf(&trash, "Incorrect version.");
+#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
+ chunk_printf(&trash, "Incorrect version. Check that the data file provided is uncompressed and Trie data format.");
+#endif
+#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
+ chunk_printf(&trash, "Incorrect version. Check that the data file provided is uncompressed and Pattern data format.");
+#endif
break;
case DATA_SET_INIT_STATUS_FILE_NOT_FOUND:
chunk_printf(&trash, "File not found.");
break;
+ case DATA_SET_INIT_STATUS_NOT_SET:
+ chunk_printf(&trash, "Data set not initialised.");
+ break;
}
if (_51d_dataset_status != DATA_SET_INIT_STATUS_SUCCESS) {
if (trash.len)
- Alert("51D Setup - Error reading 51Degrees data file: %s\n", trash.str);
+ Alert("51Degrees Setup - Error reading 51Degrees data file. %s\n", trash.str);
else
- Alert("51D Setup - Error reading 51Degrees data file.\n");
+ Alert("51Degrees Setup - Error reading 51Degrees data file.\n");
exit(1);
}
-#endif
+ free(_51d_property_list);
+#endif // USE_51DEGREES
}
static void deinit_acl_cond(struct acl_cond *cond)
@@ -1488,13 +1507,18 @@
#endif
#ifdef USE_51DEGREES
+#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
+ fiftyoneDegreesDestroy();
+#endif
+#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
fiftyoneDegreesDestroy(&global._51d_data_set);
+#endif
free(global._51d_data_file_path); global._51d_data_file_path = NULL;
list_for_each_entry_safe(_51d_prop_name, _51d_prop_nameb, &global._51d_property_names, list) {
LIST_DEL(&_51d_prop_name->list);
free(_51d_prop_name);
}
-#endif
+#endif // USE_51DEGREES
free(global.log_send_hostname); global.log_send_hostname = NULL;
free(global.log_tag); global.log_tag = NULL;
diff --git a/src/sample.c b/src/sample.c
index 6418be8..1993255 100644
--- a/src/sample.c
+++ b/src/sample.c
@@ -2130,13 +2130,64 @@
}
#ifdef USE_51DEGREES
-static int fiftyone_degrees(const struct arg *args,
- struct sample *smp, void *private)
+#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
+static int
+sample_fiftyone_degrees(const struct arg *args, struct sample *smp, void *private)
+{
+ int i; // used in loops.
+ int device_offset;
+ int property_index;
+ char no_data[] = "NoData"; // response when no data could be found.
+ struct chunk *tmp;
+
+ // use a temporary trash buffer and copy data in it
+ smp->data.str.str[smp->data.str.len] = '\0';
+
+ // perform detection.
+ device_offset = fiftyoneDegreesGetDeviceOffset(smp->data.str.str);
+
+ i = 0;
+ tmp = get_trash_chunk();
+ chunk_reset(tmp);
+
+ // loop through property names passed to the filter and fetch them from the dataset.
+ while (args[i].data.str.str) {
+ // try to find request property in dataset.
+ property_index = fiftyoneDegreesGetPropertyIndex(args[i].data.str.str);
+ if (property_index > 0) {
+ chunk_appendf(tmp, "%s", fiftyoneDegreesGetValue(device_offset, property_index));
+ }
+ else {
+ chunk_appendf(tmp, "%s", no_data);
+ }
+ // add seperator
+ if (global._51d_property_seperator)
+ chunk_appendf(tmp, "%c", global._51d_property_seperator);
+ else
+ chunk_appendf(tmp, ",");
+ ++i;
+ }
+
+ if (tmp->len) {
+ --tmp->len;
+ tmp->str[tmp->len] = '\0';
+ }
+
+ smp->data.str.str = tmp->str;
+ smp->data.str.len = strlen(smp->data.str.str);
+
+ return 1;
+}
+#endif // FIFTYONEDEGREES_H_TRIE_INCLUDED
+
+#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
+static int
+sample_fiftyone_degrees(const struct arg *args, struct sample *smp, void *private)
{
int i, j, found; // used in loops.
fiftyoneDegreesWorkset* ws; // workset for detection.
char no_data[] = "NoData"; // response when no data could be found.
- struct _51d_property_names *property;
+ const char* property_name;
struct chunk *tmp;
// use a temporary trash buffer and copy data in it
@@ -2157,17 +2208,18 @@
while (args[i].data.str.str) {
found = j = 0;
// try to find request property in dataset.
- list_for_each_entry(property, &global._51d_property_names, list) {
- if (strcmp(property->name, args[i].data.str.str) == 0) {
+ for (j = 0; j < ws->dataSet->requiredPropertyCount; j++) {
+ property_name = fiftyoneDegreesGetPropertyName(ws->dataSet, ws->dataSet->requiredProperties[j]);
+ if (strcmp(property_name, args[i].data.str.str) == 0) {
found = 1;
fiftyoneDegreesSetValues(ws, j);
chunk_appendf(tmp, "%s", fiftyoneDegreesGetValueName(ws->dataSet, *ws->values));
break;
}
- ++j;
}
- if (!found)
+ if (!found) {
chunk_appendf(tmp, "%s", no_data);
+ }
// add seperator
if (global._51d_property_seperator)
@@ -2189,7 +2241,8 @@
return 1;
}
-#endif
+#endif // FIFTYONEDEGREES_H_PATTERN_INCLUDED
+#endif // USE_51DEGREES
/************************************************************************/
@@ -2346,7 +2399,7 @@
{ "mod", sample_conv_arith_mod, ARG1(1,UINT), NULL, SMP_T_UINT, SMP_T_UINT },
{ "neg", sample_conv_arith_neg, 0, NULL, SMP_T_UINT, SMP_T_UINT },
#ifdef USE_51DEGREES
- { "51d", fiftyone_degrees, ARG5(1,STR,STR,STR,STR,STR), NULL, SMP_T_STR, SMP_T_STR },
+ { "51d", sample_fiftyone_degrees,ARG5(1,STR,STR,STR,STR,STR), NULL, SMP_T_STR, SMP_T_STR },
#endif
{ NULL, NULL, 0, 0, 0 },