blob: 03cf742c852cdb6d50301f4bcd023b37b033404b [file] [log] [blame]
Dragan Dosen93b38d92015-06-29 16:43:25 +02001#include <stdio.h>
2
3#include <common/cfgparse.h>
4#include <common/chunk.h>
5#include <proto/arg.h>
6#include <proto/log.h>
7#include <proto/sample.h>
8#include <import/xxhash.h>
9
10#include <import/51d.h>
11
12struct _51d_property_names {
13 struct list list;
14 char *name;
15};
16
17static int _51d_data_file(char **args, int section_type, struct proxy *curpx,
18 struct proxy *defpx, const char *file, int line,
19 char **err)
20{
21 if (*(args[1]) == 0) {
22 memprintf(err,
23 "'%s' expects a filepath to a 51Degrees trie or pattern data file.",
24 args[0]);
25 return -1;
26 }
27
28 if (global._51degrees.data_file_path)
29 free(global._51degrees.data_file_path);
30 global._51degrees.data_file_path = strdup(args[1]);
31
32 return 0;
33}
34
35static int _51d_property_name_list(char **args, int section_type, struct proxy *curpx,
36 struct proxy *defpx, const char *file, int line,
37 char **err)
38{
39 int cur_arg = 1;
40 struct _51d_property_names *name;
41
42 if (*(args[cur_arg]) == 0) {
43 memprintf(err,
44 "'%s' expects at least one 51Degrees property name.",
45 args[0]);
46 return -1;
47 }
48
49 while (*(args[cur_arg])) {
50 name = calloc(1, sizeof(struct _51d_property_names));
51 name->name = strdup(args[cur_arg]);
52 LIST_ADDQ(&global._51degrees.property_names, &name->list);
53 ++cur_arg;
54 }
55
56 return 0;
57}
58
59static int _51d_property_separator(char **args, int section_type, struct proxy *curpx,
60 struct proxy *defpx, const char *file, int line,
61 char **err)
62{
63 if (*(args[1]) == 0) {
64 memprintf(err,
65 "'%s' expects a single character.",
66 args[0]);
67 return -1;
68 }
69 if (strlen(args[1]) > 1) {
70 memprintf(err,
71 "'%s' expects a single character, got '%s'.",
72 args[0], args[1]);
73 return -1;
74 }
75
76 global._51degrees.property_separator = *args[1];
77
78 return 0;
79}
80
81static int _51d_conv(const struct arg *args, struct sample *smp, void *private)
82{
83 int i;
84 char no_data[] = "NoData"; /* response when no data could be found */
85 struct chunk *temp;
86#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
87 int j, found;
88 const char* property_name;
89 fiftyoneDegreesWorkset* ws; /* workset for detection */
90#endif
91#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
92 int device_offset;
93 int property_index;
94#endif
95
96#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
97 /* Create workset. This will later contain detection results. */
98 ws = fiftyoneDegreesCreateWorkset(&global._51degrees.data_set);
99 if (!ws)
100 return 0;
101#endif
102
103 smp->data.str.str[smp->data.str.len] = '\0';
104
105 /* Perform detection. */
106#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
107 fiftyoneDegreesMatch(ws, smp->data.str.str);
108#endif
109#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
110 device_offset = fiftyoneDegreesGetDeviceOffset(smp->data.str.str);
111#endif
112
113 i = 0;
114 temp = get_trash_chunk();
115 chunk_reset(temp);
116
117 /* Loop through property names passed to the filter and fetch them from the dataset. */
118 while (args[i].data.str.str) {
119 /* Try to find request property in dataset. */
120#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
121 found = 0;
122 for (j = 0; j < ws->dataSet->requiredPropertyCount; j++) {
123 property_name = fiftyoneDegreesGetPropertyName(ws->dataSet, ws->dataSet->requiredProperties[j]);
124 if (strcmp(property_name, args[i].data.str.str) == 0) {
125 found = 1;
126 fiftyoneDegreesSetValues(ws, j);
127 chunk_appendf(temp, "%s", fiftyoneDegreesGetValueName(ws->dataSet, *ws->values));
128 break;
129 }
130 }
131 if (!found) {
132 chunk_appendf(temp, "%s", no_data);
133 }
134#endif
135#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
136 property_index = fiftyoneDegreesGetPropertyIndex(args[i].data.str.str);
137 if (property_index > 0) {
138 chunk_appendf(temp, "%s", fiftyoneDegreesGetValue(device_offset, property_index));
139 }
140 else {
141 chunk_appendf(temp, "%s", no_data);
142 }
143#endif
144 /* Add separator. */
145 chunk_appendf(temp, "%c", global._51degrees.property_separator);
146 ++i;
147 }
148
149 if (temp->len) {
150 --temp->len;
151 temp->str[temp->len] = '\0';
152 }
153
154 smp->data.str.str = temp->str;
155 smp->data.str.len = strlen(smp->data.str.str);
156
157#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
158 fiftyoneDegreesFreeWorkset(ws);
159#endif
160
161 return 1;
162}
163
164int init_51degrees(void)
165{
166 int i = 0;
167 struct chunk *temp;
168 struct _51d_property_names *name;
169 char **_51d_property_list = NULL;
170 fiftyoneDegreesDataSetInitStatus _51d_dataset_status = DATA_SET_INIT_STATUS_NOT_SET;
171
172 if (!LIST_ISEMPTY(&global._51degrees.property_names)) {
173 i = 0;
174 list_for_each_entry(name, &global._51degrees.property_names, list)
175 ++i;
176 _51d_property_list = calloc(i, sizeof(char *));
177
178 i = 0;
179 list_for_each_entry(name, &global._51degrees.property_names, list)
180 _51d_property_list[i++] = name->name;
181 }
182
183#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
184 _51d_dataset_status = fiftyoneDegreesInitWithPropertyArray(global._51degrees.data_file_path, &global._51degrees.data_set, _51d_property_list, i);
185#endif
186#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
187 _51d_dataset_status = fiftyoneDegreesInitWithPropertyArray(global._51degrees.data_file_path, _51d_property_list, i);
188#endif
189
190 temp = get_trash_chunk();
191 chunk_reset(temp);
192
193 switch (_51d_dataset_status) {
194 case DATA_SET_INIT_STATUS_SUCCESS:
195 break;
196 case DATA_SET_INIT_STATUS_INSUFFICIENT_MEMORY:
197 chunk_printf(temp, "Insufficient memory.");
198 break;
199 case DATA_SET_INIT_STATUS_CORRUPT_DATA:
200#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
201 chunk_printf(temp, "Corrupt data file. Check that the data file provided is uncompressed and Pattern data format.");
202#endif
203#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
204 chunk_printf(temp, "Corrupt data file. Check that the data file provided is uncompressed and Trie data format.");
205#endif
206 break;
207 case DATA_SET_INIT_STATUS_INCORRECT_VERSION:
208#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
209 chunk_printf(temp, "Incorrect version. Check that the data file provided is uncompressed and Pattern data format.");
210#endif
211#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
212 chunk_printf(temp, "Incorrect version. Check that the data file provided is uncompressed and Trie data format.");
213#endif
214 break;
215 case DATA_SET_INIT_STATUS_FILE_NOT_FOUND:
216 chunk_printf(temp, "File not found.");
217 break;
218 case DATA_SET_INIT_STATUS_NOT_SET:
219 chunk_printf(temp, "Data set not initialised.");
220 break;
221 }
222 if (_51d_dataset_status != DATA_SET_INIT_STATUS_SUCCESS) {
223 if (temp->len)
224 Alert("51Degrees Setup - Error reading 51Degrees data file. %s\n", temp->str);
225 else
226 Alert("51Degrees Setup - Error reading 51Degrees data file.\n");
227 exit(1);
228 }
229 free(_51d_property_list);
230
231 return 0;
232}
233
234void deinit_51degrees(void)
235{
236 struct _51d_property_names *_51d_prop_name, *_51d_prop_nameb;
237
238#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
239 fiftyoneDegreesDestroy(&global._51degrees.data_set);
240#endif
241#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
242 fiftyoneDegreesDestroy();
243#endif
244
245 free(global._51degrees.data_file_path); global._51degrees.data_file_path = NULL;
246 list_for_each_entry_safe(_51d_prop_name, _51d_prop_nameb, &global._51degrees.property_names, list) {
247 LIST_DEL(&_51d_prop_name->list);
248 free(_51d_prop_name);
249 }
250}
251
252static struct cfg_kw_list _51dcfg_kws = {{ }, {
253 { CFG_GLOBAL, "51degrees-data-file", _51d_data_file },
254 { CFG_GLOBAL, "51degrees-property-name-list", _51d_property_name_list },
255 { CFG_GLOBAL, "51degrees-property-separator", _51d_property_separator },
256 { 0, NULL, NULL },
257}};
258
259/* Note: must not be declared <const> as its list will be overwritten */
260static struct sample_conv_kw_list conv_kws = {ILH, {
261 { "51d", _51d_conv, ARG5(1,STR,STR,STR,STR,STR), NULL, SMP_T_STR, SMP_T_STR },
262 { NULL, NULL, 0, 0, 0 },
263}};
264
265__attribute__((constructor))
266static void __51d_init(void)
267{
268 /* register sample fetch and format conversion keywords */
269 sample_register_convs(&conv_kws);
270 cfg_register_keywords(&_51dcfg_kws);
271}