blob: e96e0e436e5928250f0b7ba981c51a01062a2dee [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>
James Rosewella28bbd52015-09-18 18:28:52 +01005#include <common/buffer.h>
Dragan Dosen93b38d92015-06-29 16:43:25 +02006#include <proto/arg.h>
7#include <proto/log.h>
James Rosewella28bbd52015-09-18 18:28:52 +01008#include <proto/proto_http.h>
Dragan Dosen93b38d92015-06-29 16:43:25 +02009#include <proto/sample.h>
10#include <import/xxhash.h>
Dragan Dosen105c8e62015-06-29 16:43:26 +020011#include <import/lru.h>
Dragan Dosen93b38d92015-06-29 16:43:25 +020012#include <import/51d.h>
13
14struct _51d_property_names {
15 struct list list;
16 char *name;
17};
18
James Rosewella28bbd52015-09-18 18:28:52 +010019#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
20#define _51DEGREES_CONV_CACHE_KEY "_51d_conv"
21#define _51DEGREES_FETCH_CACHE_KEY "_51d_fetch"
Dragan Dosen105c8e62015-06-29 16:43:26 +020022static struct lru64_head *_51d_lru_tree = NULL;
23static unsigned long long _51d_lru_seed;
James Rosewella28bbd52015-09-18 18:28:52 +010024#endif
Dragan Dosen105c8e62015-06-29 16:43:26 +020025
Dragan Dosen93b38d92015-06-29 16:43:25 +020026static int _51d_data_file(char **args, int section_type, struct proxy *curpx,
27 struct proxy *defpx, const char *file, int line,
28 char **err)
29{
30 if (*(args[1]) == 0) {
31 memprintf(err,
32 "'%s' expects a filepath to a 51Degrees trie or pattern data file.",
33 args[0]);
34 return -1;
35 }
36
37 if (global._51degrees.data_file_path)
38 free(global._51degrees.data_file_path);
39 global._51degrees.data_file_path = strdup(args[1]);
40
41 return 0;
42}
43
44static int _51d_property_name_list(char **args, int section_type, struct proxy *curpx,
James Rosewella28bbd52015-09-18 18:28:52 +010045 struct proxy *defpx, const char *file, int line,
46 char **err)
Dragan Dosen93b38d92015-06-29 16:43:25 +020047{
48 int cur_arg = 1;
49 struct _51d_property_names *name;
50
51 if (*(args[cur_arg]) == 0) {
52 memprintf(err,
53 "'%s' expects at least one 51Degrees property name.",
54 args[0]);
55 return -1;
56 }
57
58 while (*(args[cur_arg])) {
59 name = calloc(1, sizeof(struct _51d_property_names));
60 name->name = strdup(args[cur_arg]);
61 LIST_ADDQ(&global._51degrees.property_names, &name->list);
62 ++cur_arg;
63 }
64
65 return 0;
66}
67
68static int _51d_property_separator(char **args, int section_type, struct proxy *curpx,
69 struct proxy *defpx, const char *file, int line,
70 char **err)
71{
72 if (*(args[1]) == 0) {
73 memprintf(err,
74 "'%s' expects a single character.",
75 args[0]);
76 return -1;
77 }
78 if (strlen(args[1]) > 1) {
79 memprintf(err,
80 "'%s' expects a single character, got '%s'.",
81 args[0], args[1]);
82 return -1;
83 }
84
85 global._51degrees.property_separator = *args[1];
86
87 return 0;
88}
89
Dragan Dosen105c8e62015-06-29 16:43:26 +020090static int _51d_cache_size(char **args, int section_type, struct proxy *curpx,
91 struct proxy *defpx, const char *file, int line,
92 char **err)
93{
94 if (*(args[1]) == 0) {
95 memprintf(err,
96 "'%s' expects a positive numeric value.",
97 args[0]);
98 return -1;
99 }
100
101 global._51degrees.cache_size = atoi(args[1]);
102 if (global._51degrees.cache_size < 0) {
103 memprintf(err,
104 "'%s' expects a positive numeric value, got '%s'.",
105 args[0], args[1]);
106 return -1;
107 }
108
James Rosewella28bbd52015-09-18 18:28:52 +0100109 return 0;
110}
111
112static int _51d_fetch_check(struct arg *arg, char **err_msg)
113{
114 if (global._51degrees.data_file_path)
115 return 1;
116
117 memprintf(err_msg, "51Degrees data file is not specified (parameter '51degrees-data-file')");
Dragan Dosen105c8e62015-06-29 16:43:26 +0200118 return 0;
119}
120
Dragan Dosen9373fc52015-08-07 16:41:23 +0200121static int _51d_conv_check(struct arg *arg, struct sample_conv *conv,
James Rosewella28bbd52015-09-18 18:28:52 +0100122 const char *file, int line, char **err_msg)
Dragan Dosen9373fc52015-08-07 16:41:23 +0200123{
124 if (global._51degrees.data_file_path)
125 return 1;
126
James Rosewella28bbd52015-09-18 18:28:52 +0100127 memprintf(err_msg, "51Degrees data file is not specified (parameter '51degrees-data-file')");
Dragan Dosen9373fc52015-08-07 16:41:23 +0200128 return 0;
129}
130
James Rosewella28bbd52015-09-18 18:28:52 +0100131#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
132/* Sets the important HTTP headers ahead of the detection
133 */
134static void _51d_set_headers(struct sample *smp, fiftyoneDegreesWorkset *ws)
Dragan Dosen93b38d92015-06-29 16:43:25 +0200135{
James Rosewella28bbd52015-09-18 18:28:52 +0100136 struct hdr_idx *idx;
137 struct hdr_ctx ctx;
138 const struct http_msg *msg;
Dragan Dosen93b38d92015-06-29 16:43:25 +0200139 int i;
James Rosewella28bbd52015-09-18 18:28:52 +0100140
141 idx = &smp->strm->txn->hdr_idx;
142 msg = &smp->strm->txn->req;
143
144 ws->importantHeadersCount = 0;
145
146 for (i = 0; i < global._51degrees.header_count; i++) {
147 ctx.idx = 0;
148 if (http_find_full_header2(
149 (global._51degrees.header_names + i)->str,
150 (global._51degrees.header_names + i)->len,
151 msg->chn->buf->p, idx, &ctx) == 1) {
152 ws->importantHeaders[ws->importantHeadersCount].header = ws->dataSet->httpHeaders + i;
153 ws->importantHeaders[ws->importantHeadersCount].headerValue = ctx.line + ctx.val;
154 ws->importantHeaders[ws->importantHeadersCount].headerValueLength = ctx.vlen;
155 ws->importantHeadersCount++;
156 }
157 }
158}
Dragan Dosen93b38d92015-06-29 16:43:25 +0200159#endif
James Rosewella28bbd52015-09-18 18:28:52 +0100160
Dragan Dosen93b38d92015-06-29 16:43:25 +0200161#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
James Rosewella28bbd52015-09-18 18:28:52 +0100162static void _51d_set_device_offsets(struct sample *smp)
163{
164 struct hdr_idx *idx;
165 struct hdr_ctx ctx;
166 const struct http_msg *msg;
167 int index;
168 fiftyoneDegreesDeviceOffsets *offsets = &global._51degrees.device_offsets;
Dragan Dosen105c8e62015-06-29 16:43:26 +0200169
James Rosewella28bbd52015-09-18 18:28:52 +0100170 idx = &smp->strm->txn->hdr_idx;
171 msg = &smp->strm->txn->req;
172 offsets->size = 0;
Dragan Dosen105c8e62015-06-29 16:43:26 +0200173
James Rosewella28bbd52015-09-18 18:28:52 +0100174 for (index = 0; index < global._51degrees.header_count; index++) {
175 ctx.idx = 0;
176 if (http_find_full_header2(
177 (global._51degrees.header_names + index)->str,
178 (global._51degrees.header_names + index)->len,
179 msg->chn->buf->p, idx, &ctx) == 1) {
180 (offsets->firstOffset + offsets->size)->httpHeaderOffset = *(global._51degrees.header_offsets + index);
181 (offsets->firstOffset + offsets->size)->deviceOffset = fiftyoneDegreesGetDeviceOffset(ctx.line + ctx.val);
182 offsets->size++;
Dragan Dosen105c8e62015-06-29 16:43:26 +0200183 }
184 }
James Rosewella28bbd52015-09-18 18:28:52 +0100185}
186#endif
Dragan Dosen93b38d92015-06-29 16:43:25 +0200187
188#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
James Rosewella28bbd52015-09-18 18:28:52 +0100189/* Provides a hash code for the important HTTP headers.
190 */
191unsigned long long _51d_req_hash(const struct arg *args, fiftyoneDegreesWorkset* ws)
192{
193 unsigned long long seed = _51d_lru_seed ^ (long)args;
194 unsigned long long hash = 0;
195 int i;
196 for(i = 0; i < ws->importantHeadersCount; i++) {
197 hash ^= ws->importantHeaders[i].header->headerNameOffset;
198 hash ^= XXH64(ws->importantHeaders[i].headerValue,
199 ws->importantHeaders[i].headerValueLength,
200 seed);
201 }
202 return hash;
203}
Dragan Dosen93b38d92015-06-29 16:43:25 +0200204#endif
205
Dragan Dosen93b38d92015-06-29 16:43:25 +0200206#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
James Rosewella28bbd52015-09-18 18:28:52 +0100207static void _51d_process_match(const struct arg *args, struct sample *smp, fiftyoneDegreesWorkset* ws)
208{
209 char *methodName;
Dragan Dosen93b38d92015-06-29 16:43:25 +0200210#endif
211#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
James Rosewella28bbd52015-09-18 18:28:52 +0100212static void _51d_process_match(const struct arg *args, struct sample *smp)
213{
214 char valuesBuffer[1024];
215 char **requiredProperties = fiftyoneDegreesGetRequiredPropertiesNames();
216 int requiredPropertiesCount = fiftyoneDegreesGetRequiredPropertiesCount();
217 fiftyoneDegreesDeviceOffsets *deviceOffsets = &global._51degrees.device_offsets;
218
Dragan Dosen93b38d92015-06-29 16:43:25 +0200219#endif
220
James Rosewella28bbd52015-09-18 18:28:52 +0100221 char no_data[] = "NoData"; /* response when no data could be found */
222 struct chunk *temp = get_trash_chunk();
223 int j, i = 0, found;
224 const char* property_name;
Dragan Dosen93b38d92015-06-29 16:43:25 +0200225
226 /* Loop through property names passed to the filter and fetch them from the dataset. */
227 while (args[i].data.str.str) {
228 /* Try to find request property in dataset. */
Dragan Dosen93b38d92015-06-29 16:43:25 +0200229 found = 0;
James Rosewella28bbd52015-09-18 18:28:52 +0100230#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
231 if (strcmp("Method", args[i].data.str.str) == 0) {
232 switch(ws->method) {
233 case EXACT: methodName = "Exact"; break;
234 case NUMERIC: methodName = "Numeric"; break;
235 case NEAREST: methodName = "Nearest"; break;
236 case CLOSEST: methodName = "Closest"; break;
237 default:
238 case NONE: methodName = "None"; break;
Dragan Dosen93b38d92015-06-29 16:43:25 +0200239 }
James Rosewella28bbd52015-09-18 18:28:52 +0100240 chunk_appendf(temp, "%s", methodName);
241 found = 1;
Dragan Dosen93b38d92015-06-29 16:43:25 +0200242 }
James Rosewella28bbd52015-09-18 18:28:52 +0100243 else if (strcmp("Difference", args[i].data.str.str) == 0) {
244 chunk_appendf(temp, "%d", ws->difference);
245 found = 1;
246 }
247 else if (strcmp("Rank", args[i].data.str.str) == 0) {
248 chunk_appendf(temp, "%d", fiftyoneDegreesGetSignatureRank(ws));
249 found = 1;
250 }
251 else {
252 for (j = 0; j < ws->dataSet->requiredPropertyCount; j++) {
253 property_name = fiftyoneDegreesGetPropertyName(ws->dataSet, ws->dataSet->requiredProperties[j]);
254 if (strcmp(property_name, args[i].data.str.str) == 0) {
255 found = 1;
256 fiftyoneDegreesSetValues(ws, j);
257 chunk_appendf(temp, "%s", fiftyoneDegreesGetValueName(ws->dataSet, *ws->values));
258 break;
259 }
260 }
Dragan Dosen93b38d92015-06-29 16:43:25 +0200261 }
262#endif
263#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
James Rosewella28bbd52015-09-18 18:28:52 +0100264 found = 0;
265 for (j = 0; j < requiredPropertiesCount; j++) {
266 property_name = requiredProperties[j];
267 if (strcmp(property_name, args[i].data.str.str) == 0 &&
268 fiftyoneDegreesGetValueFromOffsets(deviceOffsets, j, valuesBuffer, 1024) > 0) {
269 found = 1;
270 chunk_appendf(temp, "%s", valuesBuffer);
271 break;
272 }
Dragan Dosen93b38d92015-06-29 16:43:25 +0200273 }
James Rosewella28bbd52015-09-18 18:28:52 +0100274#endif
275 if (!found) {
Dragan Dosen93b38d92015-06-29 16:43:25 +0200276 chunk_appendf(temp, "%s", no_data);
277 }
Dragan Dosen93b38d92015-06-29 16:43:25 +0200278 /* Add separator. */
279 chunk_appendf(temp, "%c", global._51degrees.property_separator);
280 ++i;
281 }
282
283 if (temp->len) {
284 --temp->len;
285 temp->str[temp->len] = '\0';
286 }
287
Thierry FOURNIER2046c462015-08-20 13:42:12 +0200288 smp->data.u.str.str = temp->str;
James Rosewella28bbd52015-09-18 18:28:52 +0100289 smp->data.u.str.len = strlen(temp->str);
290}
291
292static int _51d_fetch(const struct arg *args, struct sample *smp, const char *kw, void *private)
293{
294#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
295 fiftyoneDegreesWorkset* ws; /* workset for detection */
296 struct lru64 *lru = NULL;
297#endif
298
299 /* Needed to ensure that the HTTP message has been fully recieved when
300 * used with TCP operation. Not required for HTTP operation.
301 * Data type has to be reset to ensure the string output is processed
302 * correctly.
303 */
304 CHECK_HTTP_MESSAGE_FIRST();
305 smp->data.type = SMP_T_STR;
306
307#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
308
309 /* Get only the headers needed for device detection so they can be used
310 * with the cache to return previous results. Pattern is slower than
311 * Trie so caching will help improve performance.
312 */
313
314 /* Get a workset from the pool which will later contain detection results. */
315 ws = fiftyoneDegreesWorksetPoolGet(global._51degrees.pool);
316 if (!ws)
317 return 0;
318
319 /* Set the important HTTP headers for this request in the workset. */
320 _51d_set_headers(smp, ws);
321
322 /* Check the cache to see if there's results for these headers already. */
323 if (_51d_lru_tree) {
324 lru = lru64_get(_51d_req_hash(args, ws),
325 _51d_lru_tree, _51DEGREES_FETCH_CACHE_KEY, 0);
326 if (lru && lru->domain) {
327 smp->flags |= SMP_F_CONST;
328 smp->data.u.str.str = lru->data;
329 smp->data.u.str.len = strlen(lru->data);
330 fiftyoneDegreesWorksetPoolRelease(global._51degrees.pool, ws);
331 return 1;
332 }
333 }
334
335 fiftyoneDegreesMatchForHttpHeaders(ws);
336
337 _51d_process_match(args, smp, ws);
338
339#endif
340
341#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
342
343 /* Trie is very fast so all the headers can be passed in and the result
344 * returned faster than the hashing algorithm process.
345 */
346 _51d_set_device_offsets(smp);
347 _51d_process_match(args, smp);
348
349#endif
350
351#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
352 fiftyoneDegreesWorksetPoolRelease(global._51degrees.pool, ws);
353 if (lru) {
354 smp->flags |= SMP_F_CONST;
355 lru64_commit(lru, strdup(smp->data.u.str.str), _51DEGREES_FETCH_CACHE_KEY, 0, free);
356 }
357#endif
358
359 return 1;
360}
Dragan Dosen93b38d92015-06-29 16:43:25 +0200361
James Rosewella28bbd52015-09-18 18:28:52 +0100362static int _51d_conv(const struct arg *args, struct sample *smp, void *private)
363{
Dragan Dosen93b38d92015-06-29 16:43:25 +0200364#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
James Rosewella28bbd52015-09-18 18:28:52 +0100365 fiftyoneDegreesWorkset* ws; /* workset for detection */
366 struct lru64 *lru = NULL;
Dragan Dosen93b38d92015-06-29 16:43:25 +0200367#endif
368
James Rosewella28bbd52015-09-18 18:28:52 +0100369#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
370
371 /* Look in the list. */
372 if (_51d_lru_tree) {
373 unsigned long long seed = _51d_lru_seed ^ (long)args;
374
375 lru = lru64_get(XXH64(smp->data.u.str.str, smp->data.u.str.len, seed),
376 _51d_lru_tree, _51DEGREES_CONV_CACHE_KEY, 0);
377 if (lru && lru->domain) {
378 smp->flags |= SMP_F_CONST;
379 smp->data.u.str.str = lru->data;
380 smp->data.u.str.len = strlen(smp->data.u.str.str);
381 return 1;
382 }
383 }
384
385 /* Create workset. This will later contain detection results. */
386 ws = fiftyoneDegreesWorksetPoolGet(global._51degrees.pool);
387 if (!ws)
388 return 0;
389#endif
390
391 /* Duplicate the data and remove the "const" flag before device detection. */
392 if (!smp_dup(smp))
393 return 0;
394
395 smp->data.u.str.str[smp->data.u.str.len] = '\0';
396
397 /* Perform detection. */
398#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
399 fiftyoneDegreesMatch(ws, smp->data.u.str.str);
400 _51d_process_match(args, smp, ws);
401#endif
402#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
403 global._51degrees.device_offsets.firstOffset->deviceOffset = fiftyoneDegreesGetDeviceOffset(smp->data.u.str.str);
404 global._51degrees.device_offsets.size = 1;
405 _51d_process_match(args, smp);
406#endif
407
408#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
409 fiftyoneDegreesWorksetPoolRelease(global._51degrees.pool, ws);
Dragan Dosen96a0be72015-07-07 16:10:43 +0200410 if (lru) {
411 smp->flags |= SMP_F_CONST;
James Rosewella28bbd52015-09-18 18:28:52 +0100412 lru64_commit(lru, strdup(smp->data.u.str.str), _51DEGREES_CONV_CACHE_KEY, 0, free);
Dragan Dosen96a0be72015-07-07 16:10:43 +0200413 }
James Rosewella28bbd52015-09-18 18:28:52 +0100414#endif
Dragan Dosen105c8e62015-06-29 16:43:26 +0200415
Dragan Dosen93b38d92015-06-29 16:43:25 +0200416 return 1;
417}
418
James Rosewella28bbd52015-09-18 18:28:52 +0100419#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
420void _51d_init_http_headers()
421{
422 int index = 0;
423 const fiftyoneDegreesAsciiString *headerName;
424 fiftyoneDegreesDataSet *ds = &global._51degrees.data_set;
425 global._51degrees.header_count = ds->httpHeadersCount;
426 global._51degrees.header_names = (struct chunk*)malloc(global._51degrees.header_count * sizeof(struct chunk));
427 for (index = 0; index < global._51degrees.header_count; index++) {
428 headerName = fiftyoneDegreesGetString(ds, ds->httpHeaders[index].headerNameOffset);
429 (global._51degrees.header_names + index)->str = (char*)&headerName->firstByte;
430 (global._51degrees.header_names + index)->len = headerName->length - 1;
431 (global._51degrees.header_names + index)->size = (global._51degrees.header_names + index)->len;
432 }
433}
434#endif
435
436#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
437void _51d_init_http_headers()
438{
439 int index = 0;
440 global._51degrees.header_count = fiftyoneDegreesGetHttpHeaderCount();
441 global._51degrees.device_offsets.firstOffset = (fiftyoneDegreesDeviceOffset*)malloc(
442 global._51degrees.header_count * sizeof(fiftyoneDegreesDeviceOffset));
443 global._51degrees.header_names = (struct chunk*)malloc(global._51degrees.header_count * sizeof(struct chunk));
444 global._51degrees.header_offsets = (int32_t*)malloc(global._51degrees.header_count * sizeof(int32_t));
445 for (index = 0; index < global._51degrees.header_count; index++) {
446 global._51degrees.header_offsets[index] = fiftyoneDegreesGetHttpHeaderNameOffset(index);
447 global._51degrees.header_names[index].str = fiftyoneDegreesGetHttpHeaderNamePointer(index);
448 global._51degrees.header_names[index].len = strlen(global._51degrees.header_names[index].str);
449 global._51degrees.header_names[index].size = global._51degrees.header_names[index].len;
450 }
451}
452#endif
453
Dragan Dosen93b38d92015-06-29 16:43:25 +0200454int init_51degrees(void)
455{
456 int i = 0;
457 struct chunk *temp;
458 struct _51d_property_names *name;
459 char **_51d_property_list = NULL;
460 fiftyoneDegreesDataSetInitStatus _51d_dataset_status = DATA_SET_INIT_STATUS_NOT_SET;
461
Dragan Dosen9373fc52015-08-07 16:41:23 +0200462 if (!global._51degrees.data_file_path)
463 return -1;
464
Dragan Dosen93b38d92015-06-29 16:43:25 +0200465 if (!LIST_ISEMPTY(&global._51degrees.property_names)) {
466 i = 0;
467 list_for_each_entry(name, &global._51degrees.property_names, list)
468 ++i;
469 _51d_property_list = calloc(i, sizeof(char *));
470
471 i = 0;
472 list_for_each_entry(name, &global._51degrees.property_names, list)
473 _51d_property_list[i++] = name->name;
474 }
475
476#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
477 _51d_dataset_status = fiftyoneDegreesInitWithPropertyArray(global._51degrees.data_file_path, &global._51degrees.data_set, _51d_property_list, i);
478#endif
479#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
480 _51d_dataset_status = fiftyoneDegreesInitWithPropertyArray(global._51degrees.data_file_path, _51d_property_list, i);
481#endif
482
483 temp = get_trash_chunk();
484 chunk_reset(temp);
485
486 switch (_51d_dataset_status) {
487 case DATA_SET_INIT_STATUS_SUCCESS:
James Rosewella28bbd52015-09-18 18:28:52 +0100488#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
489 /* only 1 workset in the pool because HAProxy is currently single threaded
490 * this value should be set to the number of threads in future versions.
491 */
492 global._51degrees.pool = fiftyoneDegreesWorksetPoolCreate(&global._51degrees.data_set, NULL, 1);
493#endif
494 _51d_init_http_headers();
Dragan Dosen93b38d92015-06-29 16:43:25 +0200495 break;
496 case DATA_SET_INIT_STATUS_INSUFFICIENT_MEMORY:
497 chunk_printf(temp, "Insufficient memory.");
498 break;
499 case DATA_SET_INIT_STATUS_CORRUPT_DATA:
500#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
501 chunk_printf(temp, "Corrupt data file. Check that the data file provided is uncompressed and Pattern data format.");
502#endif
503#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
504 chunk_printf(temp, "Corrupt data file. Check that the data file provided is uncompressed and Trie data format.");
505#endif
506 break;
507 case DATA_SET_INIT_STATUS_INCORRECT_VERSION:
508#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
509 chunk_printf(temp, "Incorrect version. Check that the data file provided is uncompressed and Pattern data format.");
510#endif
511#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
512 chunk_printf(temp, "Incorrect version. Check that the data file provided is uncompressed and Trie data format.");
513#endif
514 break;
515 case DATA_SET_INIT_STATUS_FILE_NOT_FOUND:
516 chunk_printf(temp, "File not found.");
517 break;
518 case DATA_SET_INIT_STATUS_NOT_SET:
519 chunk_printf(temp, "Data set not initialised.");
520 break;
521 }
522 if (_51d_dataset_status != DATA_SET_INIT_STATUS_SUCCESS) {
523 if (temp->len)
524 Alert("51Degrees Setup - Error reading 51Degrees data file. %s\n", temp->str);
525 else
526 Alert("51Degrees Setup - Error reading 51Degrees data file.\n");
527 exit(1);
528 }
529 free(_51d_property_list);
530
James Rosewella28bbd52015-09-18 18:28:52 +0100531#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
Dragan Dosen105c8e62015-06-29 16:43:26 +0200532 _51d_lru_seed = random();
James Rosewella28bbd52015-09-18 18:28:52 +0100533 if (global._51degrees.cache_size) {
Dragan Dosen105c8e62015-06-29 16:43:26 +0200534 _51d_lru_tree = lru64_new(global._51degrees.cache_size);
James Rosewella28bbd52015-09-18 18:28:52 +0100535 }
536#endif
Dragan Dosen105c8e62015-06-29 16:43:26 +0200537
Dragan Dosen93b38d92015-06-29 16:43:25 +0200538 return 0;
539}
540
541void deinit_51degrees(void)
542{
543 struct _51d_property_names *_51d_prop_name, *_51d_prop_nameb;
544
James Rosewella28bbd52015-09-18 18:28:52 +0100545 free(global._51degrees.header_names);
Dragan Dosen93b38d92015-06-29 16:43:25 +0200546#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
James Rosewella28bbd52015-09-18 18:28:52 +0100547 fiftyoneDegreesWorksetPoolFree(global._51degrees.pool);
548 fiftyoneDegreesDataSetFree(&global._51degrees.data_set);
Dragan Dosen93b38d92015-06-29 16:43:25 +0200549#endif
550#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
James Rosewella28bbd52015-09-18 18:28:52 +0100551 free(global._51degrees.device_offsets.firstOffset);
552 free(global._51degrees.header_offsets);
Dragan Dosen93b38d92015-06-29 16:43:25 +0200553 fiftyoneDegreesDestroy();
554#endif
555
556 free(global._51degrees.data_file_path); global._51degrees.data_file_path = NULL;
557 list_for_each_entry_safe(_51d_prop_name, _51d_prop_nameb, &global._51degrees.property_names, list) {
558 LIST_DEL(&_51d_prop_name->list);
559 free(_51d_prop_name);
560 }
Dragan Dosen105c8e62015-06-29 16:43:26 +0200561
James Rosewella28bbd52015-09-18 18:28:52 +0100562#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
Dragan Dosen105c8e62015-06-29 16:43:26 +0200563 while (lru64_destroy(_51d_lru_tree));
James Rosewella28bbd52015-09-18 18:28:52 +0100564#endif
Dragan Dosen93b38d92015-06-29 16:43:25 +0200565}
566
567static struct cfg_kw_list _51dcfg_kws = {{ }, {
568 { CFG_GLOBAL, "51degrees-data-file", _51d_data_file },
569 { CFG_GLOBAL, "51degrees-property-name-list", _51d_property_name_list },
570 { CFG_GLOBAL, "51degrees-property-separator", _51d_property_separator },
Dragan Dosen105c8e62015-06-29 16:43:26 +0200571 { CFG_GLOBAL, "51degrees-cache-size", _51d_cache_size },
Dragan Dosen93b38d92015-06-29 16:43:25 +0200572 { 0, NULL, NULL },
573}};
574
575/* Note: must not be declared <const> as its list will be overwritten */
James Rosewella28bbd52015-09-18 18:28:52 +0100576static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
577 { "51d.all", _51d_fetch, ARG5(1,STR,STR,STR,STR,STR), _51d_fetch_check, SMP_T_STR, SMP_USE_HRQHV },
578 { NULL, NULL, 0, 0, 0 },
579}};
580
581/* Note: must not be declared <const> as its list will be overwritten */
Dragan Dosen93b38d92015-06-29 16:43:25 +0200582static struct sample_conv_kw_list conv_kws = {ILH, {
James Rosewella28bbd52015-09-18 18:28:52 +0100583 { "51d.single", _51d_conv, ARG5(1,STR,STR,STR,STR,STR), _51d_conv_check, SMP_T_STR, SMP_T_STR },
Dragan Dosen93b38d92015-06-29 16:43:25 +0200584 { NULL, NULL, 0, 0, 0 },
585}};
586
587__attribute__((constructor))
588static void __51d_init(void)
589{
James Rosewella28bbd52015-09-18 18:28:52 +0100590 /* register sample fetch and conversion keywords */
591 sample_register_fetches(&sample_fetch_keywords);
Dragan Dosen93b38d92015-06-29 16:43:25 +0200592 sample_register_convs(&conv_kws);
593 cfg_register_keywords(&_51dcfg_kws);
594}