blob: 5e266d2e79085e09deb57eb669d5f482c4780b7e [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
Dragan Dosen105c8e62015-06-29 16:43:26 +020020static struct lru64_head *_51d_lru_tree = NULL;
21static unsigned long long _51d_lru_seed;
James Rosewella28bbd52015-09-18 18:28:52 +010022#endif
Dragan Dosen105c8e62015-06-29 16:43:26 +020023
Dragan Dosen93b38d92015-06-29 16:43:25 +020024static int _51d_data_file(char **args, int section_type, struct proxy *curpx,
25 struct proxy *defpx, const char *file, int line,
26 char **err)
27{
28 if (*(args[1]) == 0) {
29 memprintf(err,
30 "'%s' expects a filepath to a 51Degrees trie or pattern data file.",
31 args[0]);
32 return -1;
33 }
34
35 if (global._51degrees.data_file_path)
36 free(global._51degrees.data_file_path);
37 global._51degrees.data_file_path = strdup(args[1]);
38
39 return 0;
40}
41
42static int _51d_property_name_list(char **args, int section_type, struct proxy *curpx,
James Rosewella28bbd52015-09-18 18:28:52 +010043 struct proxy *defpx, const char *file, int line,
44 char **err)
Dragan Dosen93b38d92015-06-29 16:43:25 +020045{
46 int cur_arg = 1;
47 struct _51d_property_names *name;
48
49 if (*(args[cur_arg]) == 0) {
50 memprintf(err,
51 "'%s' expects at least one 51Degrees property name.",
52 args[0]);
53 return -1;
54 }
55
56 while (*(args[cur_arg])) {
57 name = calloc(1, sizeof(struct _51d_property_names));
58 name->name = strdup(args[cur_arg]);
59 LIST_ADDQ(&global._51degrees.property_names, &name->list);
60 ++cur_arg;
61 }
62
63 return 0;
64}
65
66static int _51d_property_separator(char **args, int section_type, struct proxy *curpx,
67 struct proxy *defpx, const char *file, int line,
68 char **err)
69{
70 if (*(args[1]) == 0) {
71 memprintf(err,
72 "'%s' expects a single character.",
73 args[0]);
74 return -1;
75 }
76 if (strlen(args[1]) > 1) {
77 memprintf(err,
78 "'%s' expects a single character, got '%s'.",
79 args[0], args[1]);
80 return -1;
81 }
82
83 global._51degrees.property_separator = *args[1];
84
85 return 0;
86}
87
Dragan Dosen105c8e62015-06-29 16:43:26 +020088static int _51d_cache_size(char **args, int section_type, struct proxy *curpx,
89 struct proxy *defpx, const char *file, int line,
90 char **err)
91{
92 if (*(args[1]) == 0) {
93 memprintf(err,
94 "'%s' expects a positive numeric value.",
95 args[0]);
96 return -1;
97 }
98
99 global._51degrees.cache_size = atoi(args[1]);
100 if (global._51degrees.cache_size < 0) {
101 memprintf(err,
102 "'%s' expects a positive numeric value, got '%s'.",
103 args[0], args[1]);
104 return -1;
105 }
106
James Rosewella28bbd52015-09-18 18:28:52 +0100107 return 0;
108}
109
110static int _51d_fetch_check(struct arg *arg, char **err_msg)
111{
112 if (global._51degrees.data_file_path)
113 return 1;
114
115 memprintf(err_msg, "51Degrees data file is not specified (parameter '51degrees-data-file')");
Dragan Dosen105c8e62015-06-29 16:43:26 +0200116 return 0;
117}
118
Dragan Dosen9373fc52015-08-07 16:41:23 +0200119static int _51d_conv_check(struct arg *arg, struct sample_conv *conv,
James Rosewella28bbd52015-09-18 18:28:52 +0100120 const char *file, int line, char **err_msg)
Dragan Dosen9373fc52015-08-07 16:41:23 +0200121{
122 if (global._51degrees.data_file_path)
123 return 1;
124
James Rosewella28bbd52015-09-18 18:28:52 +0100125 memprintf(err_msg, "51Degrees data file is not specified (parameter '51degrees-data-file')");
Dragan Dosen9373fc52015-08-07 16:41:23 +0200126 return 0;
127}
128
James Rosewella28bbd52015-09-18 18:28:52 +0100129#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
James Rosewell63426cb2015-09-18 19:53:05 +0100130/* Insert the data associated with the sample into the cache as a fresh item.
131 */
ben@51degrees.com82a9d762016-01-08 13:42:41 +0000132static void _51d_insert_cache_entry(struct sample *smp, struct lru64 *lru, void* domain)
James Rosewell63426cb2015-09-18 19:53:05 +0100133{
134 struct chunk *cache_entry = (struct chunk*)malloc(sizeof(struct chunk));
135
136 if (!cache_entry)
137 return;
138
James Rosewell63426cb2015-09-18 19:53:05 +0100139 cache_entry->str = malloc(smp->data.u.str.len + 1);
140 if (!cache_entry->str)
141 return;
142
143 memcpy(cache_entry->str, smp->data.u.str.str, smp->data.u.str.len);
144 cache_entry->str[smp->data.u.str.len] = 0;
145 cache_entry->len = smp->data.u.str.len;
ben@51degrees.com82a9d762016-01-08 13:42:41 +0000146 lru64_commit(lru, cache_entry, domain, 0, free);
James Rosewell63426cb2015-09-18 19:53:05 +0100147}
148
149/* Retrieves the data from the cache and sets the sample data to this string.
150 */
151static void _51d_retrieve_cache_entry(struct sample *smp, struct lru64 *lru)
152{
153 struct chunk *cache_entry = (struct chunk*)lru->data;
James Rosewell63426cb2015-09-18 19:53:05 +0100154 smp->data.u.str.str = cache_entry->str;
155 smp->data.u.str.len = cache_entry->len;
156}
157#endif
158
159#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
James Rosewella28bbd52015-09-18 18:28:52 +0100160/* Sets the important HTTP headers ahead of the detection
161 */
162static void _51d_set_headers(struct sample *smp, fiftyoneDegreesWorkset *ws)
Dragan Dosen93b38d92015-06-29 16:43:25 +0200163{
James Rosewella28bbd52015-09-18 18:28:52 +0100164 struct hdr_idx *idx;
165 struct hdr_ctx ctx;
166 const struct http_msg *msg;
Dragan Dosen93b38d92015-06-29 16:43:25 +0200167 int i;
James Rosewella28bbd52015-09-18 18:28:52 +0100168
169 idx = &smp->strm->txn->hdr_idx;
170 msg = &smp->strm->txn->req;
171
172 ws->importantHeadersCount = 0;
173
174 for (i = 0; i < global._51degrees.header_count; i++) {
175 ctx.idx = 0;
176 if (http_find_full_header2(
177 (global._51degrees.header_names + i)->str,
178 (global._51degrees.header_names + i)->len,
179 msg->chn->buf->p, idx, &ctx) == 1) {
180 ws->importantHeaders[ws->importantHeadersCount].header = ws->dataSet->httpHeaders + i;
181 ws->importantHeaders[ws->importantHeadersCount].headerValue = ctx.line + ctx.val;
182 ws->importantHeaders[ws->importantHeadersCount].headerValueLength = ctx.vlen;
183 ws->importantHeadersCount++;
184 }
185 }
186}
Dragan Dosen93b38d92015-06-29 16:43:25 +0200187#endif
James Rosewella28bbd52015-09-18 18:28:52 +0100188
Dragan Dosen93b38d92015-06-29 16:43:25 +0200189#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
James Rosewella28bbd52015-09-18 18:28:52 +0100190static void _51d_set_device_offsets(struct sample *smp)
191{
192 struct hdr_idx *idx;
193 struct hdr_ctx ctx;
194 const struct http_msg *msg;
195 int index;
196 fiftyoneDegreesDeviceOffsets *offsets = &global._51degrees.device_offsets;
Dragan Dosen105c8e62015-06-29 16:43:26 +0200197
James Rosewella28bbd52015-09-18 18:28:52 +0100198 idx = &smp->strm->txn->hdr_idx;
199 msg = &smp->strm->txn->req;
200 offsets->size = 0;
Dragan Dosen105c8e62015-06-29 16:43:26 +0200201
James Rosewella28bbd52015-09-18 18:28:52 +0100202 for (index = 0; index < global._51degrees.header_count; index++) {
203 ctx.idx = 0;
204 if (http_find_full_header2(
205 (global._51degrees.header_names + index)->str,
206 (global._51degrees.header_names + index)->len,
207 msg->chn->buf->p, idx, &ctx) == 1) {
208 (offsets->firstOffset + offsets->size)->httpHeaderOffset = *(global._51degrees.header_offsets + index);
209 (offsets->firstOffset + offsets->size)->deviceOffset = fiftyoneDegreesGetDeviceOffset(ctx.line + ctx.val);
210 offsets->size++;
Dragan Dosen105c8e62015-06-29 16:43:26 +0200211 }
212 }
James Rosewella28bbd52015-09-18 18:28:52 +0100213}
214#endif
Dragan Dosen93b38d92015-06-29 16:43:25 +0200215
216#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
James Rosewella28bbd52015-09-18 18:28:52 +0100217/* Provides a hash code for the important HTTP headers.
218 */
219unsigned long long _51d_req_hash(const struct arg *args, fiftyoneDegreesWorkset* ws)
220{
221 unsigned long long seed = _51d_lru_seed ^ (long)args;
222 unsigned long long hash = 0;
223 int i;
224 for(i = 0; i < ws->importantHeadersCount; i++) {
225 hash ^= ws->importantHeaders[i].header->headerNameOffset;
226 hash ^= XXH64(ws->importantHeaders[i].headerValue,
227 ws->importantHeaders[i].headerValueLength,
228 seed);
229 }
230 return hash;
231}
Dragan Dosen93b38d92015-06-29 16:43:25 +0200232#endif
233
Dragan Dosen93b38d92015-06-29 16:43:25 +0200234#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
James Rosewella28bbd52015-09-18 18:28:52 +0100235static void _51d_process_match(const struct arg *args, struct sample *smp, fiftyoneDegreesWorkset* ws)
236{
237 char *methodName;
Dragan Dosen93b38d92015-06-29 16:43:25 +0200238#endif
239#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
James Rosewella28bbd52015-09-18 18:28:52 +0100240static void _51d_process_match(const struct arg *args, struct sample *smp)
241{
242 char valuesBuffer[1024];
243 char **requiredProperties = fiftyoneDegreesGetRequiredPropertiesNames();
244 int requiredPropertiesCount = fiftyoneDegreesGetRequiredPropertiesCount();
245 fiftyoneDegreesDeviceOffsets *deviceOffsets = &global._51degrees.device_offsets;
246
Dragan Dosen93b38d92015-06-29 16:43:25 +0200247#endif
248
James Rosewella28bbd52015-09-18 18:28:52 +0100249 char no_data[] = "NoData"; /* response when no data could be found */
250 struct chunk *temp = get_trash_chunk();
251 int j, i = 0, found;
252 const char* property_name;
Dragan Dosen93b38d92015-06-29 16:43:25 +0200253
254 /* Loop through property names passed to the filter and fetch them from the dataset. */
255 while (args[i].data.str.str) {
256 /* Try to find request property in dataset. */
Dragan Dosen93b38d92015-06-29 16:43:25 +0200257 found = 0;
James Rosewella28bbd52015-09-18 18:28:52 +0100258#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
259 if (strcmp("Method", args[i].data.str.str) == 0) {
260 switch(ws->method) {
261 case EXACT: methodName = "Exact"; break;
262 case NUMERIC: methodName = "Numeric"; break;
263 case NEAREST: methodName = "Nearest"; break;
264 case CLOSEST: methodName = "Closest"; break;
265 default:
266 case NONE: methodName = "None"; break;
Dragan Dosen93b38d92015-06-29 16:43:25 +0200267 }
James Rosewella28bbd52015-09-18 18:28:52 +0100268 chunk_appendf(temp, "%s", methodName);
269 found = 1;
Dragan Dosen93b38d92015-06-29 16:43:25 +0200270 }
James Rosewella28bbd52015-09-18 18:28:52 +0100271 else if (strcmp("Difference", args[i].data.str.str) == 0) {
272 chunk_appendf(temp, "%d", ws->difference);
273 found = 1;
274 }
275 else if (strcmp("Rank", args[i].data.str.str) == 0) {
276 chunk_appendf(temp, "%d", fiftyoneDegreesGetSignatureRank(ws));
277 found = 1;
278 }
279 else {
280 for (j = 0; j < ws->dataSet->requiredPropertyCount; j++) {
281 property_name = fiftyoneDegreesGetPropertyName(ws->dataSet, ws->dataSet->requiredProperties[j]);
282 if (strcmp(property_name, args[i].data.str.str) == 0) {
283 found = 1;
284 fiftyoneDegreesSetValues(ws, j);
285 chunk_appendf(temp, "%s", fiftyoneDegreesGetValueName(ws->dataSet, *ws->values));
286 break;
287 }
288 }
Dragan Dosen93b38d92015-06-29 16:43:25 +0200289 }
290#endif
291#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
James Rosewella28bbd52015-09-18 18:28:52 +0100292 found = 0;
293 for (j = 0; j < requiredPropertiesCount; j++) {
294 property_name = requiredProperties[j];
295 if (strcmp(property_name, args[i].data.str.str) == 0 &&
296 fiftyoneDegreesGetValueFromOffsets(deviceOffsets, j, valuesBuffer, 1024) > 0) {
297 found = 1;
298 chunk_appendf(temp, "%s", valuesBuffer);
299 break;
300 }
Dragan Dosen93b38d92015-06-29 16:43:25 +0200301 }
James Rosewella28bbd52015-09-18 18:28:52 +0100302#endif
303 if (!found) {
Dragan Dosen93b38d92015-06-29 16:43:25 +0200304 chunk_appendf(temp, "%s", no_data);
305 }
Dragan Dosen93b38d92015-06-29 16:43:25 +0200306 /* Add separator. */
307 chunk_appendf(temp, "%c", global._51degrees.property_separator);
308 ++i;
309 }
310
311 if (temp->len) {
312 --temp->len;
313 temp->str[temp->len] = '\0';
314 }
315
Thierry FOURNIER2046c462015-08-20 13:42:12 +0200316 smp->data.u.str.str = temp->str;
James Rosewell63426cb2015-09-18 19:53:05 +0100317 smp->data.u.str.len = temp->len;
James Rosewella28bbd52015-09-18 18:28:52 +0100318}
319
320static int _51d_fetch(const struct arg *args, struct sample *smp, const char *kw, void *private)
321{
322#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
323 fiftyoneDegreesWorkset* ws; /* workset for detection */
324 struct lru64 *lru = NULL;
325#endif
326
327 /* Needed to ensure that the HTTP message has been fully recieved when
328 * used with TCP operation. Not required for HTTP operation.
329 * Data type has to be reset to ensure the string output is processed
330 * correctly.
331 */
332 CHECK_HTTP_MESSAGE_FIRST();
333 smp->data.type = SMP_T_STR;
334
ben@51degrees.com82a9d762016-01-08 13:42:41 +0000335 /* Flags the sample to show it uses constant memory*/
336 smp->flags |= SMP_F_CONST;
337
James Rosewella28bbd52015-09-18 18:28:52 +0100338#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
339
340 /* Get only the headers needed for device detection so they can be used
341 * with the cache to return previous results. Pattern is slower than
342 * Trie so caching will help improve performance.
343 */
344
345 /* Get a workset from the pool which will later contain detection results. */
346 ws = fiftyoneDegreesWorksetPoolGet(global._51degrees.pool);
347 if (!ws)
348 return 0;
349
350 /* Set the important HTTP headers for this request in the workset. */
351 _51d_set_headers(smp, ws);
352
353 /* Check the cache to see if there's results for these headers already. */
354 if (_51d_lru_tree) {
355 lru = lru64_get(_51d_req_hash(args, ws),
ben@51degrees.com82a9d762016-01-08 13:42:41 +0000356 _51d_lru_tree, (void*)args, 0);
James Rosewella28bbd52015-09-18 18:28:52 +0100357 if (lru && lru->domain) {
James Rosewell63426cb2015-09-18 19:53:05 +0100358 _51d_retrieve_cache_entry(smp, lru);
James Rosewella28bbd52015-09-18 18:28:52 +0100359 return 1;
360 }
361 }
362
363 fiftyoneDegreesMatchForHttpHeaders(ws);
364
365 _51d_process_match(args, smp, ws);
366
367#endif
368
369#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
370
371 /* Trie is very fast so all the headers can be passed in and the result
372 * returned faster than the hashing algorithm process.
373 */
374 _51d_set_device_offsets(smp);
375 _51d_process_match(args, smp);
376
377#endif
378
379#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
380 fiftyoneDegreesWorksetPoolRelease(global._51degrees.pool, ws);
381 if (lru) {
ben@51degrees.com82a9d762016-01-08 13:42:41 +0000382 _51d_insert_cache_entry(smp, lru, (void*)args);
James Rosewella28bbd52015-09-18 18:28:52 +0100383 }
384#endif
385
386 return 1;
387}
Dragan Dosen93b38d92015-06-29 16:43:25 +0200388
James Rosewella28bbd52015-09-18 18:28:52 +0100389static int _51d_conv(const struct arg *args, struct sample *smp, void *private)
390{
Dragan Dosen93b38d92015-06-29 16:43:25 +0200391#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
James Rosewella28bbd52015-09-18 18:28:52 +0100392 fiftyoneDegreesWorkset* ws; /* workset for detection */
393 struct lru64 *lru = NULL;
Dragan Dosen93b38d92015-06-29 16:43:25 +0200394#endif
395
ben@51degrees.com82a9d762016-01-08 13:42:41 +0000396 /* Flags the sample to show it uses constant memory*/
397 smp->flags |= SMP_F_CONST;
398
James Rosewella28bbd52015-09-18 18:28:52 +0100399#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
400
401 /* Look in the list. */
402 if (_51d_lru_tree) {
403 unsigned long long seed = _51d_lru_seed ^ (long)args;
404
405 lru = lru64_get(XXH64(smp->data.u.str.str, smp->data.u.str.len, seed),
ben@51degrees.com82a9d762016-01-08 13:42:41 +0000406 _51d_lru_tree, (void*)args, 0);
James Rosewella28bbd52015-09-18 18:28:52 +0100407 if (lru && lru->domain) {
James Rosewell63426cb2015-09-18 19:53:05 +0100408 _51d_retrieve_cache_entry(smp, lru);
James Rosewella28bbd52015-09-18 18:28:52 +0100409 return 1;
410 }
411 }
412
413 /* Create workset. This will later contain detection results. */
414 ws = fiftyoneDegreesWorksetPoolGet(global._51degrees.pool);
415 if (!ws)
416 return 0;
417#endif
418
419 /* Duplicate the data and remove the "const" flag before device detection. */
420 if (!smp_dup(smp))
421 return 0;
422
423 smp->data.u.str.str[smp->data.u.str.len] = '\0';
424
425 /* Perform detection. */
426#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
427 fiftyoneDegreesMatch(ws, smp->data.u.str.str);
428 _51d_process_match(args, smp, ws);
429#endif
430#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
431 global._51degrees.device_offsets.firstOffset->deviceOffset = fiftyoneDegreesGetDeviceOffset(smp->data.u.str.str);
432 global._51degrees.device_offsets.size = 1;
433 _51d_process_match(args, smp);
434#endif
435
436#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
437 fiftyoneDegreesWorksetPoolRelease(global._51degrees.pool, ws);
Dragan Dosen96a0be72015-07-07 16:10:43 +0200438 if (lru) {
ben@51degrees.com82a9d762016-01-08 13:42:41 +0000439 _51d_insert_cache_entry(smp, lru, (void*)args);
Dragan Dosen96a0be72015-07-07 16:10:43 +0200440 }
James Rosewella28bbd52015-09-18 18:28:52 +0100441#endif
Dragan Dosen105c8e62015-06-29 16:43:26 +0200442
Dragan Dosen93b38d92015-06-29 16:43:25 +0200443 return 1;
444}
445
James Rosewella28bbd52015-09-18 18:28:52 +0100446#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
447void _51d_init_http_headers()
448{
449 int index = 0;
450 const fiftyoneDegreesAsciiString *headerName;
451 fiftyoneDegreesDataSet *ds = &global._51degrees.data_set;
452 global._51degrees.header_count = ds->httpHeadersCount;
453 global._51degrees.header_names = (struct chunk*)malloc(global._51degrees.header_count * sizeof(struct chunk));
454 for (index = 0; index < global._51degrees.header_count; index++) {
455 headerName = fiftyoneDegreesGetString(ds, ds->httpHeaders[index].headerNameOffset);
456 (global._51degrees.header_names + index)->str = (char*)&headerName->firstByte;
457 (global._51degrees.header_names + index)->len = headerName->length - 1;
458 (global._51degrees.header_names + index)->size = (global._51degrees.header_names + index)->len;
459 }
460}
461#endif
462
463#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
464void _51d_init_http_headers()
465{
466 int index = 0;
467 global._51degrees.header_count = fiftyoneDegreesGetHttpHeaderCount();
468 global._51degrees.device_offsets.firstOffset = (fiftyoneDegreesDeviceOffset*)malloc(
469 global._51degrees.header_count * sizeof(fiftyoneDegreesDeviceOffset));
470 global._51degrees.header_names = (struct chunk*)malloc(global._51degrees.header_count * sizeof(struct chunk));
471 global._51degrees.header_offsets = (int32_t*)malloc(global._51degrees.header_count * sizeof(int32_t));
472 for (index = 0; index < global._51degrees.header_count; index++) {
473 global._51degrees.header_offsets[index] = fiftyoneDegreesGetHttpHeaderNameOffset(index);
474 global._51degrees.header_names[index].str = fiftyoneDegreesGetHttpHeaderNamePointer(index);
475 global._51degrees.header_names[index].len = strlen(global._51degrees.header_names[index].str);
476 global._51degrees.header_names[index].size = global._51degrees.header_names[index].len;
477 }
478}
479#endif
480
Dragan Dosen93b38d92015-06-29 16:43:25 +0200481int init_51degrees(void)
482{
483 int i = 0;
484 struct chunk *temp;
485 struct _51d_property_names *name;
486 char **_51d_property_list = NULL;
487 fiftyoneDegreesDataSetInitStatus _51d_dataset_status = DATA_SET_INIT_STATUS_NOT_SET;
488
Dragan Dosen9373fc52015-08-07 16:41:23 +0200489 if (!global._51degrees.data_file_path)
490 return -1;
491
Dragan Dosen93b38d92015-06-29 16:43:25 +0200492 if (!LIST_ISEMPTY(&global._51degrees.property_names)) {
493 i = 0;
494 list_for_each_entry(name, &global._51degrees.property_names, list)
495 ++i;
496 _51d_property_list = calloc(i, sizeof(char *));
497
498 i = 0;
499 list_for_each_entry(name, &global._51degrees.property_names, list)
500 _51d_property_list[i++] = name->name;
501 }
502
503#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
504 _51d_dataset_status = fiftyoneDegreesInitWithPropertyArray(global._51degrees.data_file_path, &global._51degrees.data_set, _51d_property_list, i);
505#endif
506#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
507 _51d_dataset_status = fiftyoneDegreesInitWithPropertyArray(global._51degrees.data_file_path, _51d_property_list, i);
508#endif
509
510 temp = get_trash_chunk();
511 chunk_reset(temp);
512
513 switch (_51d_dataset_status) {
514 case DATA_SET_INIT_STATUS_SUCCESS:
James Rosewella28bbd52015-09-18 18:28:52 +0100515#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
516 /* only 1 workset in the pool because HAProxy is currently single threaded
517 * this value should be set to the number of threads in future versions.
518 */
519 global._51degrees.pool = fiftyoneDegreesWorksetPoolCreate(&global._51degrees.data_set, NULL, 1);
520#endif
521 _51d_init_http_headers();
Dragan Dosen93b38d92015-06-29 16:43:25 +0200522 break;
523 case DATA_SET_INIT_STATUS_INSUFFICIENT_MEMORY:
524 chunk_printf(temp, "Insufficient memory.");
525 break;
526 case DATA_SET_INIT_STATUS_CORRUPT_DATA:
527#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
528 chunk_printf(temp, "Corrupt data file. Check that the data file provided is uncompressed and Pattern data format.");
529#endif
530#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
531 chunk_printf(temp, "Corrupt data file. Check that the data file provided is uncompressed and Trie data format.");
532#endif
533 break;
534 case DATA_SET_INIT_STATUS_INCORRECT_VERSION:
535#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
536 chunk_printf(temp, "Incorrect version. Check that the data file provided is uncompressed and Pattern data format.");
537#endif
538#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
539 chunk_printf(temp, "Incorrect version. Check that the data file provided is uncompressed and Trie data format.");
540#endif
541 break;
542 case DATA_SET_INIT_STATUS_FILE_NOT_FOUND:
543 chunk_printf(temp, "File not found.");
544 break;
545 case DATA_SET_INIT_STATUS_NOT_SET:
546 chunk_printf(temp, "Data set not initialised.");
547 break;
548 }
549 if (_51d_dataset_status != DATA_SET_INIT_STATUS_SUCCESS) {
550 if (temp->len)
551 Alert("51Degrees Setup - Error reading 51Degrees data file. %s\n", temp->str);
552 else
553 Alert("51Degrees Setup - Error reading 51Degrees data file.\n");
554 exit(1);
555 }
556 free(_51d_property_list);
557
James Rosewella28bbd52015-09-18 18:28:52 +0100558#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
Dragan Dosen105c8e62015-06-29 16:43:26 +0200559 _51d_lru_seed = random();
James Rosewella28bbd52015-09-18 18:28:52 +0100560 if (global._51degrees.cache_size) {
Dragan Dosen105c8e62015-06-29 16:43:26 +0200561 _51d_lru_tree = lru64_new(global._51degrees.cache_size);
James Rosewella28bbd52015-09-18 18:28:52 +0100562 }
563#endif
Dragan Dosen105c8e62015-06-29 16:43:26 +0200564
Dragan Dosen93b38d92015-06-29 16:43:25 +0200565 return 0;
566}
567
568void deinit_51degrees(void)
569{
570 struct _51d_property_names *_51d_prop_name, *_51d_prop_nameb;
571
James Rosewella28bbd52015-09-18 18:28:52 +0100572 free(global._51degrees.header_names);
Dragan Dosen93b38d92015-06-29 16:43:25 +0200573#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
James Rosewella28bbd52015-09-18 18:28:52 +0100574 fiftyoneDegreesWorksetPoolFree(global._51degrees.pool);
575 fiftyoneDegreesDataSetFree(&global._51degrees.data_set);
Dragan Dosen93b38d92015-06-29 16:43:25 +0200576#endif
577#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
James Rosewella28bbd52015-09-18 18:28:52 +0100578 free(global._51degrees.device_offsets.firstOffset);
579 free(global._51degrees.header_offsets);
Dragan Dosen93b38d92015-06-29 16:43:25 +0200580 fiftyoneDegreesDestroy();
581#endif
582
583 free(global._51degrees.data_file_path); global._51degrees.data_file_path = NULL;
584 list_for_each_entry_safe(_51d_prop_name, _51d_prop_nameb, &global._51degrees.property_names, list) {
585 LIST_DEL(&_51d_prop_name->list);
586 free(_51d_prop_name);
587 }
Dragan Dosen105c8e62015-06-29 16:43:26 +0200588
James Rosewella28bbd52015-09-18 18:28:52 +0100589#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
Dragan Dosen105c8e62015-06-29 16:43:26 +0200590 while (lru64_destroy(_51d_lru_tree));
James Rosewella28bbd52015-09-18 18:28:52 +0100591#endif
Dragan Dosen93b38d92015-06-29 16:43:25 +0200592}
593
594static struct cfg_kw_list _51dcfg_kws = {{ }, {
595 { CFG_GLOBAL, "51degrees-data-file", _51d_data_file },
596 { CFG_GLOBAL, "51degrees-property-name-list", _51d_property_name_list },
597 { CFG_GLOBAL, "51degrees-property-separator", _51d_property_separator },
Dragan Dosen105c8e62015-06-29 16:43:26 +0200598 { CFG_GLOBAL, "51degrees-cache-size", _51d_cache_size },
Dragan Dosen93b38d92015-06-29 16:43:25 +0200599 { 0, NULL, NULL },
600}};
601
602/* Note: must not be declared <const> as its list will be overwritten */
James Rosewella28bbd52015-09-18 18:28:52 +0100603static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
604 { "51d.all", _51d_fetch, ARG5(1,STR,STR,STR,STR,STR), _51d_fetch_check, SMP_T_STR, SMP_USE_HRQHV },
605 { NULL, NULL, 0, 0, 0 },
606}};
607
608/* Note: must not be declared <const> as its list will be overwritten */
Dragan Dosen93b38d92015-06-29 16:43:25 +0200609static struct sample_conv_kw_list conv_kws = {ILH, {
James Rosewella28bbd52015-09-18 18:28:52 +0100610 { "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 +0200611 { NULL, NULL, 0, 0, 0 },
612}};
613
614__attribute__((constructor))
615static void __51d_init(void)
616{
James Rosewella28bbd52015-09-18 18:28:52 +0100617 /* register sample fetch and conversion keywords */
618 sample_register_fetches(&sample_fetch_keywords);
Dragan Dosen93b38d92015-06-29 16:43:25 +0200619 sample_register_convs(&conv_kws);
620 cfg_register_keywords(&_51dcfg_kws);
621}