blob: cf32346cea1969df54331d8b7252c49dcd3d1fc7 [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
James Rosewell63426cb2015-09-18 19:53:05 +0100132/* Insert the data associated with the sample into the cache as a fresh item.
133 */
134static void _51d_insert_cache_entry(struct sample *smp, struct lru64 *lru)
135{
136 struct chunk *cache_entry = (struct chunk*)malloc(sizeof(struct chunk));
137
138 if (!cache_entry)
139 return;
140
141 smp->flags |= SMP_F_CONST;
142 cache_entry->str = malloc(smp->data.u.str.len + 1);
143 if (!cache_entry->str)
144 return;
145
146 memcpy(cache_entry->str, smp->data.u.str.str, smp->data.u.str.len);
147 cache_entry->str[smp->data.u.str.len] = 0;
148 cache_entry->len = smp->data.u.str.len;
149 lru64_commit(lru, cache_entry, _51DEGREES_CONV_CACHE_KEY, 0, free);
150}
151
152/* Retrieves the data from the cache and sets the sample data to this string.
153 */
154static void _51d_retrieve_cache_entry(struct sample *smp, struct lru64 *lru)
155{
156 struct chunk *cache_entry = (struct chunk*)lru->data;
157 smp->flags |= SMP_F_CONST;
158 smp->data.u.str.str = cache_entry->str;
159 smp->data.u.str.len = cache_entry->len;
160}
161#endif
162
163#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
James Rosewella28bbd52015-09-18 18:28:52 +0100164/* Sets the important HTTP headers ahead of the detection
165 */
166static void _51d_set_headers(struct sample *smp, fiftyoneDegreesWorkset *ws)
Dragan Dosen93b38d92015-06-29 16:43:25 +0200167{
James Rosewella28bbd52015-09-18 18:28:52 +0100168 struct hdr_idx *idx;
169 struct hdr_ctx ctx;
170 const struct http_msg *msg;
Dragan Dosen93b38d92015-06-29 16:43:25 +0200171 int i;
James Rosewella28bbd52015-09-18 18:28:52 +0100172
173 idx = &smp->strm->txn->hdr_idx;
174 msg = &smp->strm->txn->req;
175
176 ws->importantHeadersCount = 0;
177
178 for (i = 0; i < global._51degrees.header_count; i++) {
179 ctx.idx = 0;
180 if (http_find_full_header2(
181 (global._51degrees.header_names + i)->str,
182 (global._51degrees.header_names + i)->len,
183 msg->chn->buf->p, idx, &ctx) == 1) {
184 ws->importantHeaders[ws->importantHeadersCount].header = ws->dataSet->httpHeaders + i;
185 ws->importantHeaders[ws->importantHeadersCount].headerValue = ctx.line + ctx.val;
186 ws->importantHeaders[ws->importantHeadersCount].headerValueLength = ctx.vlen;
187 ws->importantHeadersCount++;
188 }
189 }
190}
Dragan Dosen93b38d92015-06-29 16:43:25 +0200191#endif
James Rosewella28bbd52015-09-18 18:28:52 +0100192
Dragan Dosen93b38d92015-06-29 16:43:25 +0200193#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
James Rosewella28bbd52015-09-18 18:28:52 +0100194static void _51d_set_device_offsets(struct sample *smp)
195{
196 struct hdr_idx *idx;
197 struct hdr_ctx ctx;
198 const struct http_msg *msg;
199 int index;
200 fiftyoneDegreesDeviceOffsets *offsets = &global._51degrees.device_offsets;
Dragan Dosen105c8e62015-06-29 16:43:26 +0200201
James Rosewella28bbd52015-09-18 18:28:52 +0100202 idx = &smp->strm->txn->hdr_idx;
203 msg = &smp->strm->txn->req;
204 offsets->size = 0;
Dragan Dosen105c8e62015-06-29 16:43:26 +0200205
James Rosewella28bbd52015-09-18 18:28:52 +0100206 for (index = 0; index < global._51degrees.header_count; index++) {
207 ctx.idx = 0;
208 if (http_find_full_header2(
209 (global._51degrees.header_names + index)->str,
210 (global._51degrees.header_names + index)->len,
211 msg->chn->buf->p, idx, &ctx) == 1) {
212 (offsets->firstOffset + offsets->size)->httpHeaderOffset = *(global._51degrees.header_offsets + index);
213 (offsets->firstOffset + offsets->size)->deviceOffset = fiftyoneDegreesGetDeviceOffset(ctx.line + ctx.val);
214 offsets->size++;
Dragan Dosen105c8e62015-06-29 16:43:26 +0200215 }
216 }
James Rosewella28bbd52015-09-18 18:28:52 +0100217}
218#endif
Dragan Dosen93b38d92015-06-29 16:43:25 +0200219
220#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
James Rosewella28bbd52015-09-18 18:28:52 +0100221/* Provides a hash code for the important HTTP headers.
222 */
223unsigned long long _51d_req_hash(const struct arg *args, fiftyoneDegreesWorkset* ws)
224{
225 unsigned long long seed = _51d_lru_seed ^ (long)args;
226 unsigned long long hash = 0;
227 int i;
228 for(i = 0; i < ws->importantHeadersCount; i++) {
229 hash ^= ws->importantHeaders[i].header->headerNameOffset;
230 hash ^= XXH64(ws->importantHeaders[i].headerValue,
231 ws->importantHeaders[i].headerValueLength,
232 seed);
233 }
234 return hash;
235}
Dragan Dosen93b38d92015-06-29 16:43:25 +0200236#endif
237
Dragan Dosen93b38d92015-06-29 16:43:25 +0200238#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
James Rosewella28bbd52015-09-18 18:28:52 +0100239static void _51d_process_match(const struct arg *args, struct sample *smp, fiftyoneDegreesWorkset* ws)
240{
241 char *methodName;
Dragan Dosen93b38d92015-06-29 16:43:25 +0200242#endif
243#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
James Rosewella28bbd52015-09-18 18:28:52 +0100244static void _51d_process_match(const struct arg *args, struct sample *smp)
245{
246 char valuesBuffer[1024];
247 char **requiredProperties = fiftyoneDegreesGetRequiredPropertiesNames();
248 int requiredPropertiesCount = fiftyoneDegreesGetRequiredPropertiesCount();
249 fiftyoneDegreesDeviceOffsets *deviceOffsets = &global._51degrees.device_offsets;
250
Dragan Dosen93b38d92015-06-29 16:43:25 +0200251#endif
252
James Rosewella28bbd52015-09-18 18:28:52 +0100253 char no_data[] = "NoData"; /* response when no data could be found */
254 struct chunk *temp = get_trash_chunk();
255 int j, i = 0, found;
256 const char* property_name;
Dragan Dosen93b38d92015-06-29 16:43:25 +0200257
258 /* Loop through property names passed to the filter and fetch them from the dataset. */
259 while (args[i].data.str.str) {
260 /* Try to find request property in dataset. */
Dragan Dosen93b38d92015-06-29 16:43:25 +0200261 found = 0;
James Rosewella28bbd52015-09-18 18:28:52 +0100262#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
263 if (strcmp("Method", args[i].data.str.str) == 0) {
264 switch(ws->method) {
265 case EXACT: methodName = "Exact"; break;
266 case NUMERIC: methodName = "Numeric"; break;
267 case NEAREST: methodName = "Nearest"; break;
268 case CLOSEST: methodName = "Closest"; break;
269 default:
270 case NONE: methodName = "None"; break;
Dragan Dosen93b38d92015-06-29 16:43:25 +0200271 }
James Rosewella28bbd52015-09-18 18:28:52 +0100272 chunk_appendf(temp, "%s", methodName);
273 found = 1;
Dragan Dosen93b38d92015-06-29 16:43:25 +0200274 }
James Rosewella28bbd52015-09-18 18:28:52 +0100275 else if (strcmp("Difference", args[i].data.str.str) == 0) {
276 chunk_appendf(temp, "%d", ws->difference);
277 found = 1;
278 }
279 else if (strcmp("Rank", args[i].data.str.str) == 0) {
280 chunk_appendf(temp, "%d", fiftyoneDegreesGetSignatureRank(ws));
281 found = 1;
282 }
283 else {
284 for (j = 0; j < ws->dataSet->requiredPropertyCount; j++) {
285 property_name = fiftyoneDegreesGetPropertyName(ws->dataSet, ws->dataSet->requiredProperties[j]);
286 if (strcmp(property_name, args[i].data.str.str) == 0) {
287 found = 1;
288 fiftyoneDegreesSetValues(ws, j);
289 chunk_appendf(temp, "%s", fiftyoneDegreesGetValueName(ws->dataSet, *ws->values));
290 break;
291 }
292 }
Dragan Dosen93b38d92015-06-29 16:43:25 +0200293 }
294#endif
295#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
James Rosewella28bbd52015-09-18 18:28:52 +0100296 found = 0;
297 for (j = 0; j < requiredPropertiesCount; j++) {
298 property_name = requiredProperties[j];
299 if (strcmp(property_name, args[i].data.str.str) == 0 &&
300 fiftyoneDegreesGetValueFromOffsets(deviceOffsets, j, valuesBuffer, 1024) > 0) {
301 found = 1;
302 chunk_appendf(temp, "%s", valuesBuffer);
303 break;
304 }
Dragan Dosen93b38d92015-06-29 16:43:25 +0200305 }
James Rosewella28bbd52015-09-18 18:28:52 +0100306#endif
307 if (!found) {
Dragan Dosen93b38d92015-06-29 16:43:25 +0200308 chunk_appendf(temp, "%s", no_data);
309 }
Dragan Dosen93b38d92015-06-29 16:43:25 +0200310 /* Add separator. */
311 chunk_appendf(temp, "%c", global._51degrees.property_separator);
312 ++i;
313 }
314
315 if (temp->len) {
316 --temp->len;
317 temp->str[temp->len] = '\0';
318 }
319
Thierry FOURNIER2046c462015-08-20 13:42:12 +0200320 smp->data.u.str.str = temp->str;
James Rosewell63426cb2015-09-18 19:53:05 +0100321 smp->data.u.str.len = temp->len;
James Rosewella28bbd52015-09-18 18:28:52 +0100322}
323
324static int _51d_fetch(const struct arg *args, struct sample *smp, const char *kw, void *private)
325{
326#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
327 fiftyoneDegreesWorkset* ws; /* workset for detection */
328 struct lru64 *lru = NULL;
329#endif
330
331 /* Needed to ensure that the HTTP message has been fully recieved when
332 * used with TCP operation. Not required for HTTP operation.
333 * Data type has to be reset to ensure the string output is processed
334 * correctly.
335 */
336 CHECK_HTTP_MESSAGE_FIRST();
337 smp->data.type = SMP_T_STR;
338
339#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
340
341 /* Get only the headers needed for device detection so they can be used
342 * with the cache to return previous results. Pattern is slower than
343 * Trie so caching will help improve performance.
344 */
345
346 /* Get a workset from the pool which will later contain detection results. */
347 ws = fiftyoneDegreesWorksetPoolGet(global._51degrees.pool);
348 if (!ws)
349 return 0;
350
351 /* Set the important HTTP headers for this request in the workset. */
352 _51d_set_headers(smp, ws);
353
354 /* Check the cache to see if there's results for these headers already. */
355 if (_51d_lru_tree) {
356 lru = lru64_get(_51d_req_hash(args, ws),
357 _51d_lru_tree, _51DEGREES_FETCH_CACHE_KEY, 0);
358 if (lru && lru->domain) {
James Rosewell63426cb2015-09-18 19:53:05 +0100359 _51d_retrieve_cache_entry(smp, lru);
James Rosewella28bbd52015-09-18 18:28:52 +0100360 return 1;
361 }
362 }
363
364 fiftyoneDegreesMatchForHttpHeaders(ws);
365
366 _51d_process_match(args, smp, ws);
367
368#endif
369
370#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
371
372 /* Trie is very fast so all the headers can be passed in and the result
373 * returned faster than the hashing algorithm process.
374 */
375 _51d_set_device_offsets(smp);
376 _51d_process_match(args, smp);
377
378#endif
379
380#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
381 fiftyoneDegreesWorksetPoolRelease(global._51degrees.pool, ws);
382 if (lru) {
James Rosewell63426cb2015-09-18 19:53:05 +0100383 _51d_insert_cache_entry(smp, lru);
James Rosewella28bbd52015-09-18 18:28:52 +0100384 }
385#endif
386
387 return 1;
388}
Dragan Dosen93b38d92015-06-29 16:43:25 +0200389
James Rosewella28bbd52015-09-18 18:28:52 +0100390static int _51d_conv(const struct arg *args, struct sample *smp, void *private)
391{
Dragan Dosen93b38d92015-06-29 16:43:25 +0200392#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
James Rosewella28bbd52015-09-18 18:28:52 +0100393 fiftyoneDegreesWorkset* ws; /* workset for detection */
394 struct lru64 *lru = NULL;
Dragan Dosen93b38d92015-06-29 16:43:25 +0200395#endif
396
James Rosewella28bbd52015-09-18 18:28:52 +0100397#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
398
399 /* Look in the list. */
400 if (_51d_lru_tree) {
401 unsigned long long seed = _51d_lru_seed ^ (long)args;
402
403 lru = lru64_get(XXH64(smp->data.u.str.str, smp->data.u.str.len, seed),
404 _51d_lru_tree, _51DEGREES_CONV_CACHE_KEY, 0);
405 if (lru && lru->domain) {
James Rosewell63426cb2015-09-18 19:53:05 +0100406 _51d_retrieve_cache_entry(smp, lru);
James Rosewella28bbd52015-09-18 18:28:52 +0100407 return 1;
408 }
409 }
410
411 /* Create workset. This will later contain detection results. */
412 ws = fiftyoneDegreesWorksetPoolGet(global._51degrees.pool);
413 if (!ws)
414 return 0;
415#endif
416
417 /* Duplicate the data and remove the "const" flag before device detection. */
418 if (!smp_dup(smp))
419 return 0;
420
421 smp->data.u.str.str[smp->data.u.str.len] = '\0';
422
423 /* Perform detection. */
424#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
425 fiftyoneDegreesMatch(ws, smp->data.u.str.str);
426 _51d_process_match(args, smp, ws);
427#endif
428#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
429 global._51degrees.device_offsets.firstOffset->deviceOffset = fiftyoneDegreesGetDeviceOffset(smp->data.u.str.str);
430 global._51degrees.device_offsets.size = 1;
431 _51d_process_match(args, smp);
432#endif
433
434#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
435 fiftyoneDegreesWorksetPoolRelease(global._51degrees.pool, ws);
Dragan Dosen96a0be72015-07-07 16:10:43 +0200436 if (lru) {
James Rosewell63426cb2015-09-18 19:53:05 +0100437 _51d_insert_cache_entry(smp, lru);
Dragan Dosen96a0be72015-07-07 16:10:43 +0200438 }
James Rosewella28bbd52015-09-18 18:28:52 +0100439#endif
Dragan Dosen105c8e62015-06-29 16:43:26 +0200440
Dragan Dosen93b38d92015-06-29 16:43:25 +0200441 return 1;
442}
443
James Rosewella28bbd52015-09-18 18:28:52 +0100444#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
445void _51d_init_http_headers()
446{
447 int index = 0;
448 const fiftyoneDegreesAsciiString *headerName;
449 fiftyoneDegreesDataSet *ds = &global._51degrees.data_set;
450 global._51degrees.header_count = ds->httpHeadersCount;
451 global._51degrees.header_names = (struct chunk*)malloc(global._51degrees.header_count * sizeof(struct chunk));
452 for (index = 0; index < global._51degrees.header_count; index++) {
453 headerName = fiftyoneDegreesGetString(ds, ds->httpHeaders[index].headerNameOffset);
454 (global._51degrees.header_names + index)->str = (char*)&headerName->firstByte;
455 (global._51degrees.header_names + index)->len = headerName->length - 1;
456 (global._51degrees.header_names + index)->size = (global._51degrees.header_names + index)->len;
457 }
458}
459#endif
460
461#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
462void _51d_init_http_headers()
463{
464 int index = 0;
465 global._51degrees.header_count = fiftyoneDegreesGetHttpHeaderCount();
466 global._51degrees.device_offsets.firstOffset = (fiftyoneDegreesDeviceOffset*)malloc(
467 global._51degrees.header_count * sizeof(fiftyoneDegreesDeviceOffset));
468 global._51degrees.header_names = (struct chunk*)malloc(global._51degrees.header_count * sizeof(struct chunk));
469 global._51degrees.header_offsets = (int32_t*)malloc(global._51degrees.header_count * sizeof(int32_t));
470 for (index = 0; index < global._51degrees.header_count; index++) {
471 global._51degrees.header_offsets[index] = fiftyoneDegreesGetHttpHeaderNameOffset(index);
472 global._51degrees.header_names[index].str = fiftyoneDegreesGetHttpHeaderNamePointer(index);
473 global._51degrees.header_names[index].len = strlen(global._51degrees.header_names[index].str);
474 global._51degrees.header_names[index].size = global._51degrees.header_names[index].len;
475 }
476}
477#endif
478
Dragan Dosen93b38d92015-06-29 16:43:25 +0200479int init_51degrees(void)
480{
481 int i = 0;
482 struct chunk *temp;
483 struct _51d_property_names *name;
484 char **_51d_property_list = NULL;
485 fiftyoneDegreesDataSetInitStatus _51d_dataset_status = DATA_SET_INIT_STATUS_NOT_SET;
486
Dragan Dosen9373fc52015-08-07 16:41:23 +0200487 if (!global._51degrees.data_file_path)
488 return -1;
489
Dragan Dosen93b38d92015-06-29 16:43:25 +0200490 if (!LIST_ISEMPTY(&global._51degrees.property_names)) {
491 i = 0;
492 list_for_each_entry(name, &global._51degrees.property_names, list)
493 ++i;
494 _51d_property_list = calloc(i, sizeof(char *));
495
496 i = 0;
497 list_for_each_entry(name, &global._51degrees.property_names, list)
498 _51d_property_list[i++] = name->name;
499 }
500
501#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
502 _51d_dataset_status = fiftyoneDegreesInitWithPropertyArray(global._51degrees.data_file_path, &global._51degrees.data_set, _51d_property_list, i);
503#endif
504#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
505 _51d_dataset_status = fiftyoneDegreesInitWithPropertyArray(global._51degrees.data_file_path, _51d_property_list, i);
506#endif
507
508 temp = get_trash_chunk();
509 chunk_reset(temp);
510
511 switch (_51d_dataset_status) {
512 case DATA_SET_INIT_STATUS_SUCCESS:
James Rosewella28bbd52015-09-18 18:28:52 +0100513#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
514 /* only 1 workset in the pool because HAProxy is currently single threaded
515 * this value should be set to the number of threads in future versions.
516 */
517 global._51degrees.pool = fiftyoneDegreesWorksetPoolCreate(&global._51degrees.data_set, NULL, 1);
518#endif
519 _51d_init_http_headers();
Dragan Dosen93b38d92015-06-29 16:43:25 +0200520 break;
521 case DATA_SET_INIT_STATUS_INSUFFICIENT_MEMORY:
522 chunk_printf(temp, "Insufficient memory.");
523 break;
524 case DATA_SET_INIT_STATUS_CORRUPT_DATA:
525#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
526 chunk_printf(temp, "Corrupt data file. Check that the data file provided is uncompressed and Pattern data format.");
527#endif
528#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
529 chunk_printf(temp, "Corrupt data file. Check that the data file provided is uncompressed and Trie data format.");
530#endif
531 break;
532 case DATA_SET_INIT_STATUS_INCORRECT_VERSION:
533#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
534 chunk_printf(temp, "Incorrect version. Check that the data file provided is uncompressed and Pattern data format.");
535#endif
536#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
537 chunk_printf(temp, "Incorrect version. Check that the data file provided is uncompressed and Trie data format.");
538#endif
539 break;
540 case DATA_SET_INIT_STATUS_FILE_NOT_FOUND:
541 chunk_printf(temp, "File not found.");
542 break;
543 case DATA_SET_INIT_STATUS_NOT_SET:
544 chunk_printf(temp, "Data set not initialised.");
545 break;
546 }
547 if (_51d_dataset_status != DATA_SET_INIT_STATUS_SUCCESS) {
548 if (temp->len)
549 Alert("51Degrees Setup - Error reading 51Degrees data file. %s\n", temp->str);
550 else
551 Alert("51Degrees Setup - Error reading 51Degrees data file.\n");
552 exit(1);
553 }
554 free(_51d_property_list);
555
James Rosewella28bbd52015-09-18 18:28:52 +0100556#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
Dragan Dosen105c8e62015-06-29 16:43:26 +0200557 _51d_lru_seed = random();
James Rosewella28bbd52015-09-18 18:28:52 +0100558 if (global._51degrees.cache_size) {
Dragan Dosen105c8e62015-06-29 16:43:26 +0200559 _51d_lru_tree = lru64_new(global._51degrees.cache_size);
James Rosewella28bbd52015-09-18 18:28:52 +0100560 }
561#endif
Dragan Dosen105c8e62015-06-29 16:43:26 +0200562
Dragan Dosen93b38d92015-06-29 16:43:25 +0200563 return 0;
564}
565
566void deinit_51degrees(void)
567{
568 struct _51d_property_names *_51d_prop_name, *_51d_prop_nameb;
569
James Rosewella28bbd52015-09-18 18:28:52 +0100570 free(global._51degrees.header_names);
Dragan Dosen93b38d92015-06-29 16:43:25 +0200571#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
James Rosewella28bbd52015-09-18 18:28:52 +0100572 fiftyoneDegreesWorksetPoolFree(global._51degrees.pool);
573 fiftyoneDegreesDataSetFree(&global._51degrees.data_set);
Dragan Dosen93b38d92015-06-29 16:43:25 +0200574#endif
575#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
James Rosewella28bbd52015-09-18 18:28:52 +0100576 free(global._51degrees.device_offsets.firstOffset);
577 free(global._51degrees.header_offsets);
Dragan Dosen93b38d92015-06-29 16:43:25 +0200578 fiftyoneDegreesDestroy();
579#endif
580
581 free(global._51degrees.data_file_path); global._51degrees.data_file_path = NULL;
582 list_for_each_entry_safe(_51d_prop_name, _51d_prop_nameb, &global._51degrees.property_names, list) {
583 LIST_DEL(&_51d_prop_name->list);
584 free(_51d_prop_name);
585 }
Dragan Dosen105c8e62015-06-29 16:43:26 +0200586
James Rosewella28bbd52015-09-18 18:28:52 +0100587#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
Dragan Dosen105c8e62015-06-29 16:43:26 +0200588 while (lru64_destroy(_51d_lru_tree));
James Rosewella28bbd52015-09-18 18:28:52 +0100589#endif
Dragan Dosen93b38d92015-06-29 16:43:25 +0200590}
591
592static struct cfg_kw_list _51dcfg_kws = {{ }, {
593 { CFG_GLOBAL, "51degrees-data-file", _51d_data_file },
594 { CFG_GLOBAL, "51degrees-property-name-list", _51d_property_name_list },
595 { CFG_GLOBAL, "51degrees-property-separator", _51d_property_separator },
Dragan Dosen105c8e62015-06-29 16:43:26 +0200596 { CFG_GLOBAL, "51degrees-cache-size", _51d_cache_size },
Dragan Dosen93b38d92015-06-29 16:43:25 +0200597 { 0, NULL, NULL },
598}};
599
600/* Note: must not be declared <const> as its list will be overwritten */
James Rosewella28bbd52015-09-18 18:28:52 +0100601static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
602 { "51d.all", _51d_fetch, ARG5(1,STR,STR,STR,STR,STR), _51d_fetch_check, SMP_T_STR, SMP_USE_HRQHV },
603 { NULL, NULL, 0, 0, 0 },
604}};
605
606/* Note: must not be declared <const> as its list will be overwritten */
Dragan Dosen93b38d92015-06-29 16:43:25 +0200607static struct sample_conv_kw_list conv_kws = {ILH, {
James Rosewella28bbd52015-09-18 18:28:52 +0100608 { "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 +0200609 { NULL, NULL, 0, 0, 0 },
610}};
611
612__attribute__((constructor))
613static void __51d_init(void)
614{
James Rosewella28bbd52015-09-18 18:28:52 +0100615 /* register sample fetch and conversion keywords */
616 sample_register_fetches(&sample_fetch_keywords);
Dragan Dosen93b38d92015-06-29 16:43:25 +0200617 sample_register_convs(&conv_kws);
618 cfg_register_keywords(&_51dcfg_kws);
619}