Browse code

geoip2: log errors for cases where the container could not evaluated and add docs

- log errors for cases where the container could not evaluated due to missing
initialization of the pvc container because no actual access is done in the cfg
- add documentation describing that at least one access to the container is necessary
for the match function to work correctly

Henning Westerholt authored on 09/05/2022 16:43:22
Showing 1 changed files
... ...
@@ -565,14 +565,14 @@ int geoip2_update_pv(str *tomatch, str *name)
565 565
 
566 566
 	if(tomatch->len>255)
567 567
 	{
568
-		LM_DBG("target too long (max 255): %s\n", tomatch->s);
568
+		LM_ERR("target too long (max 255): %s\n", tomatch->s);
569 569
 		return -3;
570 570
 	}
571 571
 
572 572
 	gr = sr_geoip2_get_record(name);
573 573
 	if(gr==NULL)
574 574
 	{
575
-		LM_DBG("container not found: %s\n", tomatch->s);
575
+		LM_ERR("container not found: %s\n", tomatch->s);
576 576
 		return - 4;
577 577
 	}
578 578
 
Browse code

geoip2: fix logging for reload failures, initialize memory for db

Henning Westerholt authored on 13/04/2022 08:20:54
Showing 1 changed files
... ...
@@ -490,6 +490,8 @@ int geoip2_init_pv(char *path)
490 490
 {
491 491
 	int status;
492 492
 	_handle_GeoIP = shm_malloc(sizeof(struct MMDB_s));
493
+	memset(_handle_GeoIP, 0, sizeof(struct MMDB_s));
494
+
493 495
 	if (_handle_GeoIP == NULL)
494 496
 	{
495 497
 		SHM_MEM_ERROR;
... ...
@@ -522,9 +524,13 @@ int geoip2_reload_pv(char *path)
522 524
 	if(MMDB_SUCCESS != status)
523 525
 	{
524 526
 		LM_ERR("cannot reload GeoIP database file at: %s\n", path);
527
+
528
+	}
529
+	else
530
+	{
531
+		LM_INFO("reloaded GeoIP database file at: %s\n", path);
525 532
 	}
526 533
 	lock_release(lock);
527
-	LM_INFO("reloaded GeoIP database file at: %s\n", path);
528 534
 
529 535
 	return status;
530 536
 }
Browse code

geoip2: add reload RCP command fuctionality (related to GH #2029)

Henning Westerholt authored on 13/04/2022 06:34:02
Showing 1 changed files
... ...
@@ -29,6 +29,7 @@
29 29
 #include "../../core/dprint.h"
30 30
 #include "../../core/hashes.h"
31 31
 #include "../../core/pvar.h"
32
+#include "../../core/locking.h"
32 33
 
33 34
 #include "geoip2_pv.h"
34 35
 
... ...
@@ -61,7 +62,8 @@ typedef struct _geoip2_pv {
61 62
 	int type;
62 63
 } geoip2_pv_t;
63 64
 
64
-static MMDB_s _handle_GeoIP;
65
+static MMDB_s *_handle_GeoIP;
66
+static gen_lock_t *lock = NULL;
65 67
 
66 68
 static sr_geoip2_item_t *_sr_geoip2_list = NULL;
67 69
 
... ...
@@ -239,6 +241,44 @@ int pv_geoip2_get_strzval(struct sip_msg *msg, pv_param_t *param,
239 241
 	return pv_get_strval(msg, param, res, &s);
240 242
 }
241 243
 
244
+static int get_mmdb_value2(MMDB_entry_s *entry, MMDB_entry_data_s *data,
245
+		const char *first, const char *second)
246
+{
247
+	int status = 0;
248
+
249
+	lock_get(lock);
250
+	status = MMDB_get_value(entry, data, first, second, NULL);
251
+	lock_release(lock);
252
+
253
+	return status;
254
+}
255
+
256
+static int get_mmdb_value3(MMDB_entry_s *entry, MMDB_entry_data_s *data,
257
+		const char *first, const char *second, const char *third)
258
+{
259
+	int status = 0;
260
+
261
+	lock_get(lock);
262
+	status = MMDB_get_value(entry, data, first, second, third, NULL);
263
+	lock_release(lock);
264
+
265
+	return status;
266
+}
267
+
268
+static int get_mmdb_value4(MMDB_entry_s *entry, MMDB_entry_data_s *data,
269
+		const char *first, const char *second, const char *third,
270
+		const char *fourth)
271
+{
272
+	int status = 0;
273
+
274
+	lock_get(lock);
275
+	status = MMDB_get_value(entry, data, first, second, third, fourth, NULL);
276
+	lock_release(lock);
277
+
278
+	return status;
279
+}
280
+
281
+
242 282
 int pv_get_geoip2(struct sip_msg *msg, pv_param_t *param,
243 283
 		pv_value_t *res)
244 284
 {
... ...
@@ -261,9 +301,8 @@ int pv_get_geoip2(struct sip_msg *msg, pv_param_t *param,
261 301
 			{
262 302
 				if(gpv->item->r.flags&1)
263 303
 					return pv_get_null(msg, param, res);
264
-				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
265
-					"location","time_zone", NULL
266
-					) != MMDB_SUCCESS)
304
+				if(get_mmdb_value2(&gpv->item->r.record.entry, &entry_data,
305
+					"location","time_zone") != MMDB_SUCCESS)
267 306
 					return pv_get_null(msg, param, res);
268 307
 				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
269 308
 					gpv->item->r.time_zone.s = (char *)entry_data.utf8_string;
... ...
@@ -277,8 +316,8 @@ int pv_get_geoip2(struct sip_msg *msg, pv_param_t *param,
277 316
 			{
278 317
 				if(gpv->item->r.flags&32)
279 318
 					return pv_get_null(msg, param, res);
280
-				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
281
-					"postal","code", NULL) != MMDB_SUCCESS)
319
+				if(get_mmdb_value2(&gpv->item->r.record.entry, &entry_data,
320
+					"postal","code") != MMDB_SUCCESS)
282 321
 					return pv_get_null(msg, param, res);
283 322
 				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
284 323
 					gpv->item->r.zip.s = (char *)entry_data.utf8_string;
... ...
@@ -291,8 +330,8 @@ int pv_get_geoip2(struct sip_msg *msg, pv_param_t *param,
291 330
 			if((gpv->item->r.flags&2)==0)
292 331
 			{
293 332
 				gpv->item->r.latitude[0] = '\0';
294
-				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
295
-					"location","latitude", NULL) != MMDB_SUCCESS)
333
+				if(get_mmdb_value2(&gpv->item->r.record.entry, &entry_data,
334
+					"location","latitude") != MMDB_SUCCESS)
296 335
 					return pv_get_null(msg, param, res);
297 336
 				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_DOUBLE)
298 337
 					snprintf(gpv->item->r.latitude, 15, "%f", entry_data.double_value);
... ...
@@ -304,8 +343,8 @@ int pv_get_geoip2(struct sip_msg *msg, pv_param_t *param,
304 343
 			if((gpv->item->r.flags&4)==0)
305 344
 			{
306 345
 				gpv->item->r.latitude[0] = '\0';
307
-				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
308
-					"location","longitude", NULL) != MMDB_SUCCESS)
346
+				if(get_mmdb_value2(&gpv->item->r.record.entry, &entry_data,
347
+					"location","longitude") != MMDB_SUCCESS)
309 348
 					return pv_get_null(msg, param, res);
310 349
 				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_DOUBLE)
311 350
 					snprintf(gpv->item->r.longitude, 15, "%f", entry_data.double_value);
... ...
@@ -318,9 +357,8 @@ int pv_get_geoip2(struct sip_msg *msg, pv_param_t *param,
318 357
 			{
319 358
 				if(gpv->item->r.flags&16)
320 359
 					return pv_get_null(msg, param, res);
321
-				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
322
-					"continent","code", NULL
323
-					) != MMDB_SUCCESS)
360
+				if(get_mmdb_value2(&gpv->item->r.record.entry, &entry_data,
361
+					"continent","code") != MMDB_SUCCESS)
324 362
 					return pv_get_null(msg, param, res);
325 363
 				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
326 364
 					gpv->item->r.cont_code.s = (char *)entry_data.utf8_string;
... ...
@@ -334,9 +372,8 @@ int pv_get_geoip2(struct sip_msg *msg, pv_param_t *param,
334 372
 			{
335 373
 				if(gpv->item->r.flags&64)
336 374
 					return pv_get_null(msg, param, res);
337
-				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
338
-					"city","names","en", NULL
339
-					) != MMDB_SUCCESS)
375
+				if(get_mmdb_value3(&gpv->item->r.record.entry, &entry_data,
376
+					"city","names","en") != MMDB_SUCCESS)
340 377
 					return pv_get_null(msg, param, res);
341 378
 				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
342 379
 					gpv->item->r.city.s = (char *)entry_data.utf8_string;
... ...
@@ -350,9 +387,8 @@ int pv_get_geoip2(struct sip_msg *msg, pv_param_t *param,
350 387
 			{
351 388
 				if(gpv->item->r.flags&128)
352 389
 					return pv_get_null(msg, param, res);
353
-				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
354
-					"subdivisions","0","iso_code", NULL
355
-					) != MMDB_SUCCESS)
390
+				if(get_mmdb_value3(&gpv->item->r.record.entry, &entry_data,
391
+					"subdivisions","0","iso_code") != MMDB_SUCCESS)
356 392
 					return pv_get_null(msg, param, res);
357 393
 				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
358 394
 					gpv->item->r.region_code.s = (char *)entry_data.utf8_string;
... ...
@@ -366,9 +402,8 @@ int pv_get_geoip2(struct sip_msg *msg, pv_param_t *param,
366 402
 			{
367 403
 				if(gpv->item->r.flags&16)
368 404
 					return pv_get_null(msg, param, res);
369
-				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
370
-					"subdivisions","0","names","en", NULL
371
-					) != MMDB_SUCCESS)
405
+				if(get_mmdb_value4(&gpv->item->r.record.entry, &entry_data,
406
+					"subdivisions","0","names","en") != MMDB_SUCCESS)
372 407
 					return pv_get_null(msg, param, res);
373 408
 				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
374 409
 					gpv->item->r.region_name.s = (char *)entry_data.utf8_string;
... ...
@@ -381,8 +416,8 @@ int pv_get_geoip2(struct sip_msg *msg, pv_param_t *param,
381 416
 			if((gpv->item->r.flags&256)==0)
382 417
 			{
383 418
 				gpv->item->r.metro[0] = '\0';
384
-				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
385
-					"location","metro_code", NULL) != MMDB_SUCCESS)
419
+				if(get_mmdb_value2(&gpv->item->r.record.entry, &entry_data,
420
+					"location","metro_code") != MMDB_SUCCESS)
386 421
 					return pv_get_null(msg, param, res);
387 422
 				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UINT16)
388 423
 					snprintf(gpv->item->r.metro, 15, "%hd", entry_data.uint16);
... ...
@@ -404,20 +439,18 @@ int pv_get_geoip2(struct sip_msg *msg, pv_param_t *param,
404 439
 			{
405 440
 				if(gpv->item->r.flags&512)
406 441
 					return pv_get_null(msg, param, res);
407
-				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
408
-					"country","iso_code", NULL
409
-					) != MMDB_SUCCESS
410
-					&& MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
411
-						"registered_country","iso_code", NULL
412
-						) != MMDB_SUCCESS
442
+				if(get_mmdb_value2(&gpv->item->r.record.entry, &entry_data,
443
+					"country","iso_code") != MMDB_SUCCESS
444
+					&& get_mmdb_value2(&gpv->item->r.record.entry, &entry_data,
445
+						"registered_country","iso_code") != MMDB_SUCCESS
413 446
 					)
414 447
 					return pv_get_null(msg, param, res);
415 448
 				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
416 449
 					gpv->item->r.country.s = (char *)entry_data.utf8_string;
417 450
 					gpv->item->r.country.len = entry_data.data_size;
418 451
 				}
419
-				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
420
-					"traits","is_anonymous_proxy", NULL) == MMDB_SUCCESS
452
+				if(get_mmdb_value2(&gpv->item->r.record.entry, &entry_data,
453
+					"traits","is_anonymous_proxy") == MMDB_SUCCESS
421 454
 					&& entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_BOOLEAN
422 455
 					&& entry_data.boolean) {
423 456
 					gpv->item->r.country.s = "A1";
... ...
@@ -429,25 +462,83 @@ int pv_get_geoip2(struct sip_msg *msg, pv_param_t *param,
429 462
 	}
430 463
 }
431 464
 
465
+static int init_shmlock(void)
466
+{
467
+	lock = lock_alloc();
468
+	if (!lock) {
469
+		LM_CRIT("cannot allocate memory for lock\n");
470
+		return -1;
471
+	}
472
+	if (lock_init(lock) == 0) {
473
+		LM_CRIT("cannot initialize lock\n");
474
+		return -1;
475
+	}
476
+
477
+	return 0;
478
+}
479
+
480
+static void destroy_shmlock(void)
481
+{
482
+	if (lock) {
483
+		lock_destroy(lock);
484
+		lock_dealloc((void *)lock);
485
+		lock = NULL;
486
+	}
487
+}
488
+
432 489
 int geoip2_init_pv(char *path)
433 490
 {
434
-	int status = MMDB_open(path, MMDB_MODE_MMAP, &_handle_GeoIP);
491
+	int status;
492
+	_handle_GeoIP = shm_malloc(sizeof(struct MMDB_s));
493
+	if (_handle_GeoIP == NULL)
494
+	{
495
+		SHM_MEM_ERROR;
496
+		return -1;
497
+	}
498
+
499
+	status = MMDB_open(path, MMDB_MODE_MMAP, _handle_GeoIP);
435 500
 
436 501
 	if(MMDB_SUCCESS != status)
437 502
 	{
438 503
 		LM_ERR("cannot open GeoIP database file at: %s\n", path);
439 504
 		return -1;
440 505
 	}
506
+
507
+	if (init_shmlock() != 0)
508
+	{
509
+		LM_ERR("cannot create GeoIP database lock\n");
510
+		return -1;
511
+	}
441 512
 	return 0;
442 513
 }
443 514
 
515
+int geoip2_reload_pv(char *path)
516
+{
517
+	int status = 0;
518
+
519
+	lock_get(lock);
520
+	MMDB_close(_handle_GeoIP);
521
+	status = MMDB_open(path, MMDB_MODE_MMAP, _handle_GeoIP);
522
+	if(MMDB_SUCCESS != status)
523
+	{
524
+		LM_ERR("cannot reload GeoIP database file at: %s\n", path);
525
+	}
526
+	lock_release(lock);
527
+	LM_INFO("reloaded GeoIP database file at: %s\n", path);
528
+
529
+	return status;
530
+}
531
+
444 532
 void geoip2_destroy_list(void)
445 533
 {
446 534
 }
447 535
 
448 536
 void geoip2_destroy_pv(void)
449 537
 {
450
-	MMDB_close(&_handle_GeoIP);
538
+	MMDB_close(_handle_GeoIP);
539
+	shm_free(_handle_GeoIP);
540
+	_handle_GeoIP = NULL;
541
+	destroy_shmlock();
451 542
 }
452 543
 
453 544
 void geoip2_pv_reset(str *name)
... ...
@@ -481,10 +572,12 @@ int geoip2_update_pv(str *tomatch, str *name)
481 572
 
482 573
 	strncpy(gr->tomatch, tomatch->s, tomatch->len);
483 574
 	tomatch->s[tomatch->len] = '\0';
484
-	gr->record = MMDB_lookup_string(&_handle_GeoIP,
575
+	lock_get(lock);
576
+	gr->record = MMDB_lookup_string(_handle_GeoIP,
485 577
 			(const char*)gr->tomatch,
486 578
 			&gai_error, &mmdb_error
487 579
 			);
580
+	lock_release(lock);
488 581
 	LM_DBG("attempt to match: %s\n", gr->tomatch);
489 582
 	if (gai_error || MMDB_SUCCESS != mmdb_error || !gr->record.found_entry)
490 583
 	{
Browse code

geoip2: removed unneeded lib kmi from Makefile

- bits of formatting and removed svn ids

Daniel-Constantin Mierla authored on 02/01/2017 08:10:18
Showing 1 changed files
... ...
@@ -1,5 +1,4 @@
1 1
 /**
2
- * $Id$
3 2
  *
4 3
  * This file is part of Kamailio, a free SIP server.
5 4
  *
... ...
@@ -178,14 +177,14 @@ int pv_parse_geoip2_name(pv_spec_p sp, str *in)
178 177
 
179 178
 	switch(pvs.len)
180 179
 	{
181
-		case 2: 
180
+		case 2:
182 181
 			if(strncmp(pvs.s, "cc", 2)==0)
183 182
 				gpv->type = 0;
184 183
 			else if(strncmp(pvs.s, "tz", 2)==0)
185 184
 				gpv->type = 1;
186 185
 			else goto error;
187 186
 		break;
188
-		case 3: 
187
+		case 3:
189 188
 			if(strncmp(pvs.s, "zip", 3)==0)
190 189
 				gpv->type = 2;
191 190
 			else if(strncmp(pvs.s, "lat", 3)==0)
... ...
@@ -194,7 +193,7 @@ int pv_parse_geoip2_name(pv_spec_p sp, str *in)
194 193
 				gpv->type = 4;
195 194
 			else goto error;
196 195
 		break;
197
-		case 4: 
196
+		case 4:
198 197
 			if(strncmp(pvs.s, "city", 4)==0)
199 198
 				gpv->type = 8;
200 199
 			else if(strncmp(pvs.s, "regc", 4)==0)
... ...
@@ -203,7 +202,7 @@ int pv_parse_geoip2_name(pv_spec_p sp, str *in)
203 202
 				gpv->type = 11;
204 203
 			else goto error;
205 204
 		break;
206
-		case 5: 
205
+		case 5:
207 206
 			if(strncmp(pvs.s, "metro", 5)==0)
208 207
 				gpv->type = 12;
209 208
 			else if(strncmp(pvs.s, "nmask", 5)==0)
... ...
@@ -433,7 +432,7 @@ int pv_get_geoip2(struct sip_msg *msg, pv_param_t *param,
433 432
 int geoip2_init_pv(char *path)
434 433
 {
435 434
 	int status = MMDB_open(path, MMDB_MODE_MMAP, &_handle_GeoIP);
436
-	
435
+
437 436
 	if(MMDB_SUCCESS != status)
438 437
 	{
439 438
 		LM_ERR("cannot open GeoIP database file at: %s\n", path);
... ...
@@ -454,7 +453,7 @@ void geoip2_destroy_pv(void)
454 453
 void geoip2_pv_reset(str *name)
455 454
 {
456 455
 	sr_geoip2_record_t *gr = NULL;
457
-	
456
+
458 457
 	gr = sr_geoip2_get_record(name);
459 458
 
460 459
 	if(gr==NULL)
... ...
@@ -466,13 +465,13 @@ int geoip2_update_pv(str *tomatch, str *name)
466 465
 {
467 466
 	sr_geoip2_record_t *gr = NULL;
468 467
 	int gai_error, mmdb_error;
469
-	
468
+
470 469
 	if(tomatch->len>255)
471 470
 	{
472 471
 		LM_DBG("target too long (max 255): %s\n", tomatch->s);
473 472
 		return -3;
474 473
 	}
475
-	
474
+
476 475
 	gr = sr_geoip2_get_record(name);
477 476
 	if(gr==NULL)
478 477
 	{
Browse code

core, lib, modules: updated include paths for header files

Daniel-Constantin Mierla authored on 07/12/2016 11:07:22
Showing 1 changed files
... ...
@@ -27,9 +27,9 @@
27 27
 #include <stdlib.h>
28 28
 #include <time.h>
29 29
 
30
-#include "../../dprint.h"
31
-#include "../../hashes.h"
32
-#include "../../pvar.h"
30
+#include "../../core/dprint.h"
31
+#include "../../core/hashes.h"
32
+#include "../../core/pvar.h"
33 33
 
34 34
 #include "geoip2_pv.h"
35 35
 
Browse code

core, lib, modules: restructured source code tree

- new folder src/ to hold the source code for main project applications
- main.c is in src/
- all core files are subfolder are in src/core/
- modules are in src/modules/
- libs are in src/lib/
- application Makefiles are in src/
- application binary is built in src/ (src/kamailio)

Daniel-Constantin Mierla authored on 07/12/2016 11:03:51
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,499 @@
1
+/**
2
+ * $Id$
3
+ *
4
+ * This file is part of Kamailio, a free SIP server.
5
+ *
6
+ * This file is free software; you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation; either version 2 of the License, or
9
+ * (at your option) any later version
10
+ *
11
+ *
12
+ * This file is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ * GNU General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License
18
+ * along with this program; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20
+ *
21
+ */
22
+
23
+
24
+#include <assert.h>
25
+#include <ctype.h>
26
+#include <string.h>
27
+#include <stdlib.h>
28
+#include <time.h>
29
+
30
+#include "../../dprint.h"
31
+#include "../../hashes.h"
32
+#include "../../pvar.h"
33
+
34
+#include "geoip2_pv.h"
35
+
36
+typedef struct _sr_geoip2_record {
37
+	MMDB_lookup_result_s record;
38
+	str time_zone;
39
+	str zip;
40
+	str city;
41
+	str region_code;
42
+	str region_name;
43
+	str country;
44
+	str cont_code;
45
+	char latitude[16];
46
+	char longitude[16];
47
+	char metro[16];
48
+	char nmask[8];
49
+	char tomatch[256];
50
+	int flags;
51
+} sr_geoip2_record_t;
52
+
53
+typedef struct _sr_geoip2_item {
54
+	str pvclass;
55
+	unsigned int hashid;
56
+	sr_geoip2_record_t r;
57
+	struct _sr_geoip2_item *next;
58
+} sr_geoip2_item_t;
59
+
60
+typedef struct _geoip2_pv {
61
+	sr_geoip2_item_t *item;
62
+	int type;
63
+} geoip2_pv_t;
64
+
65
+static MMDB_s _handle_GeoIP;
66
+
67
+static sr_geoip2_item_t *_sr_geoip2_list = NULL;
68
+
69
+sr_geoip2_record_t *sr_geoip2_get_record(str *name)
70
+{
71
+	sr_geoip2_item_t *it = NULL;
72
+	unsigned int hashid = 0;
73
+
74
+	hashid =  get_hash1_raw(name->s, name->len);
75
+
76
+	it = _sr_geoip2_list;
77
+	while(it!=NULL)
78
+	{
79
+		if(it->hashid==hashid && it->pvclass.len == name->len
80
+				&& strncmp(it->pvclass.s, name->s, name->len)==0)
81
+			return &it->r;
82
+		it = it->next;
83
+	}
84
+	return NULL;
85
+}
86
+
87
+sr_geoip2_item_t *sr_geoip2_add_item(str *name)
88
+{
89
+	sr_geoip2_item_t *it = NULL;
90
+	unsigned int hashid = 0;
91
+
92
+	hashid =  get_hash1_raw(name->s, name->len);
93
+
94
+	it = _sr_geoip2_list;
95
+	while(it!=NULL)
96
+	{
97
+		if(it->hashid==hashid && it->pvclass.len == name->len
98
+				&& strncmp(it->pvclass.s, name->s, name->len)==0)
99
+			return it;
100
+		it = it->next;
101
+	}
102
+	/* add new */
103
+	it = (sr_geoip2_item_t*)pkg_malloc(sizeof(sr_geoip2_item_t));
104
+	if(it==NULL)
105
+	{
106
+		LM_ERR("no more pkg\n");
107
+		return NULL;
108
+	}
109
+	memset(it, 0, sizeof(sr_geoip2_item_t));
110
+	it->pvclass.s = (char*)pkg_malloc(name->len+1);
111
+	if(it->pvclass.s==NULL)
112
+	{
113
+		LM_ERR("no more pkg.\n");
114
+		pkg_free(it);
115
+		return NULL;
116
+	}
117
+	memcpy(it->pvclass.s, name->s, name->len);
118
+	it->pvclass.s[name->len] = '\0';
119
+	it->pvclass.len = name->len;
120
+	it->hashid = hashid;
121
+	it->next = _sr_geoip2_list;
122
+	_sr_geoip2_list = it;
123
+	return it;
124
+}
125
+
126
+
127
+int pv_parse_geoip2_name(pv_spec_p sp, str *in)
128
+{
129
+	geoip2_pv_t *gpv=NULL;
130
+	char *p;
131
+	str pvc;
132
+	str pvs;
133
+	if(sp==NULL || in==NULL || in->len<=0)
134
+		return -1;
135
+
136
+	gpv = (geoip2_pv_t*)pkg_malloc(sizeof(geoip2_pv_t));
137
+	if(gpv==NULL)
138
+		return -1;
139
+
140
+	memset(gpv, 0, sizeof(geoip2_pv_t));
141
+
142
+	p = in->s;
143
+
144
+	while(p<in->s+in->len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
145
+		p++;
146
+	if(p>in->s+in->len || *p=='\0')
147
+		goto error;
148
+	pvc.s = p;
149
+	while(p < in->s + in->len)
150
+	{
151
+		if(*p=='=' || *p==' ' || *p=='\t' || *p=='\n' || *p=='\r')
152
+			break;
153
+		p++;
154
+	}
155
+	if(p>in->s+in->len || *p=='\0')
156
+		goto error;
157
+	pvc.len = p - pvc.s;
158
+	if(*p!='=')
159
+	{
160
+		while(p<in->s+in->len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
161
+			p++;
162
+		if(p>in->s+in->len || *p=='\0' || *p!='=')
163
+			goto error;
164
+	}
165
+	p++;
166
+	if(*p!='>')
167
+		goto error;
168
+	p++;
169
+
170
+	pvs.len = in->len - (int)(p - in->s);
171
+	pvs.s = p;
172
+	LM_DBG("geoip2 [%.*s] - key [%.*s]\n", pvc.len, pvc.s,
173
+			pvs.len, pvs.s);
174
+
175
+	gpv->item = sr_geoip2_add_item(&pvc);
176
+	if(gpv->item==NULL)
177
+		goto error;
178
+
179
+	switch(pvs.len)
180
+	{
181
+		case 2: 
182
+			if(strncmp(pvs.s, "cc", 2)==0)
183
+				gpv->type = 0;
184
+			else if(strncmp(pvs.s, "tz", 2)==0)
185
+				gpv->type = 1;
186
+			else goto error;
187
+		break;
188
+		case 3: 
189
+			if(strncmp(pvs.s, "zip", 3)==0)
190
+				gpv->type = 2;
191
+			else if(strncmp(pvs.s, "lat", 3)==0)
192
+				gpv->type = 3;
193
+			else if(strncmp(pvs.s, "lon", 3)==0)
194
+				gpv->type = 4;
195
+			else goto error;
196
+		break;
197
+		case 4: 
198
+			if(strncmp(pvs.s, "city", 4)==0)
199
+				gpv->type = 8;
200
+			else if(strncmp(pvs.s, "regc", 4)==0)
201
+				gpv->type = 10;
202
+			else if(strncmp(pvs.s, "regn", 4)==0)
203
+				gpv->type = 11;
204
+			else goto error;
205
+		break;
206
+		case 5: 
207
+			if(strncmp(pvs.s, "metro", 5)==0)
208
+				gpv->type = 12;
209
+			else if(strncmp(pvs.s, "nmask", 5)==0)
210
+				gpv->type = 13;
211
+			else if(strncmp(pvs.s, "contc", 5)==0)
212
+				gpv->type = 6;
213
+			else goto error;
214
+		break;
215
+		default:
216
+			goto error;
217
+	}
218
+	sp->pvp.pvn.u.dname = (void*)gpv;
219
+	sp->pvp.pvn.type = PV_NAME_OTHER;
220
+
221
+	return 0;
222
+
223
+error:
224
+	if(gpv!=NULL)
225
+		pkg_free(gpv);
226
+
227
+	LM_ERR("error at PV geoip2 name: %.*s\n", in->len, in->s);
228
+	return -1;
229
+}
230
+
231
+int pv_geoip2_get_strzval(struct sip_msg *msg, pv_param_t *param,
232
+		pv_value_t *res, char *sval)
233
+{
234
+	str s;
235
+	if(sval==NULL)
236
+		return pv_get_null(msg, param, res);
237
+
238
+	s.s = sval;
239
+	s.len = strlen(s.s);
240
+	return pv_get_strval(msg, param, res, &s);
241
+}
242
+
243
+int pv_get_geoip2(struct sip_msg *msg, pv_param_t *param,
244
+		pv_value_t *res)
245
+{
246
+	geoip2_pv_t *gpv;
247
+	MMDB_entry_data_s entry_data;
248
+
249
+	if(msg==NULL || param==NULL)
250
+		return -1;
251
+
252
+	gpv = (geoip2_pv_t*)param->pvn.u.dname;
253
+	if(gpv==NULL)
254
+		return -1;
255
+	if(gpv->item==NULL)
256
+		return pv_get_null(msg, param, res);
257
+
258
+	switch(gpv->type)
259
+	{
260
+		case 1: /* tz */
261
+			if(gpv->item->r.time_zone.s==NULL)
262
+			{
263
+				if(gpv->item->r.flags&1)
264
+					return pv_get_null(msg, param, res);
265
+				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
266
+					"location","time_zone", NULL
267
+					) != MMDB_SUCCESS)
268
+					return pv_get_null(msg, param, res);
269
+				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
270
+					gpv->item->r.time_zone.s = (char *)entry_data.utf8_string;
271
+					gpv->item->r.time_zone.len = entry_data.data_size;
272
+				}
273
+				gpv->item->r.flags |= 1;
274
+			}
275
+			return pv_get_strval(msg, param, res, &gpv->item->r.time_zone);
276
+		case 2: /* zip */
277
+			if(gpv->item->r.zip.s==NULL)
278
+			{
279
+				if(gpv->item->r.flags&32)
280
+					return pv_get_null(msg, param, res);
281
+				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
282
+					"postal","code", NULL) != MMDB_SUCCESS)
283
+					return pv_get_null(msg, param, res);
284
+				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
285
+					gpv->item->r.zip.s = (char *)entry_data.utf8_string;
286
+					gpv->item->r.zip.len = entry_data.data_size;
287
+				}
288
+				gpv->item->r.flags |= 32;
289
+			}
290
+			return pv_get_strval(msg, param, res, &gpv->item->r.zip);
291
+		case 3: /* lat */
292
+			if((gpv->item->r.flags&2)==0)
293
+			{
294
+				gpv->item->r.latitude[0] = '\0';
295
+				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
296
+					"location","latitude", NULL) != MMDB_SUCCESS)
297
+					return pv_get_null(msg, param, res);
298
+				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_DOUBLE)
299
+					snprintf(gpv->item->r.latitude, 15, "%f", entry_data.double_value);
300
+				gpv->item->r.flags |= 2;
301
+			}
302
+			return pv_geoip2_get_strzval(msg, param, res,
303
+					gpv->item->r.latitude);
304
+		case 4: /* lon */
305
+			if((gpv->item->r.flags&4)==0)
306
+			{
307
+				gpv->item->r.latitude[0] = '\0';
308
+				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
309
+					"location","longitude", NULL) != MMDB_SUCCESS)
310
+					return pv_get_null(msg, param, res);
311
+				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_DOUBLE)
312
+					snprintf(gpv->item->r.longitude, 15, "%f", entry_data.double_value);
313
+				gpv->item->r.flags |= 4;
314
+			}
315
+			return pv_geoip2_get_strzval(msg, param, res,
316
+					gpv->item->r.longitude);
317
+		case 6: /* contc */
318
+			if(gpv->item->r.cont_code.s==NULL)
319
+			{
320
+				if(gpv->item->r.flags&16)
321
+					return pv_get_null(msg, param, res);
322
+				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
323
+					"continent","code", NULL
324
+					) != MMDB_SUCCESS)
325
+					return pv_get_null(msg, param, res);
326
+				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
327
+					gpv->item->r.cont_code.s = (char *)entry_data.utf8_string;
328
+					gpv->item->r.cont_code.len = entry_data.data_size;
329
+				}
330
+				gpv->item->r.flags |= 16;
331
+			}
332
+			return pv_get_strval(msg, param, res, &gpv->item->r.cont_code);
333
+		case 8: /* city */
334
+			if(gpv->item->r.city.s==NULL)
335
+			{
336
+				if(gpv->item->r.flags&64)
337
+					return pv_get_null(msg, param, res);
338
+				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
339
+					"city","names","en", NULL
340
+					) != MMDB_SUCCESS)
341
+					return pv_get_null(msg, param, res);
342
+				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
343
+					gpv->item->r.city.s = (char *)entry_data.utf8_string;
344
+					gpv->item->r.city.len = entry_data.data_size;
345
+				}
346
+				gpv->item->r.flags |= 64;
347
+			}
348
+			return pv_get_strval(msg, param, res, &gpv->item->r.city);
349
+		case 10: /* regc */
350
+			if(gpv->item->r.region_code.s==NULL)
351
+			{
352
+				if(gpv->item->r.flags&128)
353
+					return pv_get_null(msg, param, res);
354
+				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
355
+					"subdivisions","0","iso_code", NULL
356
+					) != MMDB_SUCCESS)
357
+					return pv_get_null(msg, param, res);
358
+				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
359
+					gpv->item->r.region_code.s = (char *)entry_data.utf8_string;
360
+					gpv->item->r.region_code.len = entry_data.data_size;
361
+				}
362
+				gpv->item->r.flags |= 128;
363
+			}
364
+			return pv_get_strval(msg, param, res, &gpv->item->r.region_code);
365
+		case 11: /* regn */
366
+			if(gpv->item->r.region_name.s==NULL)
367
+			{
368
+				if(gpv->item->r.flags&16)
369
+					return pv_get_null(msg, param, res);
370
+				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
371
+					"subdivisions","0","names","en", NULL
372
+					) != MMDB_SUCCESS)
373
+					return pv_get_null(msg, param, res);
374
+				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
375
+					gpv->item->r.region_name.s = (char *)entry_data.utf8_string;
376
+					gpv->item->r.region_name.len = entry_data.data_size;
377
+				}
378
+				gpv->item->r.flags |= 16;
379
+			}
380
+			return pv_get_strval(msg, param, res, &gpv->item->r.region_name);
381
+		case 12: /* metro */
382
+			if((gpv->item->r.flags&256)==0)
383
+			{
384
+				gpv->item->r.metro[0] = '\0';
385
+				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
386
+					"location","metro_code", NULL) != MMDB_SUCCESS)
387
+					return pv_get_null(msg, param, res);
388
+				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UINT16)
389
+					snprintf(gpv->item->r.metro, 15, "%hd", entry_data.uint16);
390
+				gpv->item->r.flags |= 256;
391
+			}
392
+			return pv_geoip2_get_strzval(msg, param, res,
393
+					gpv->item->r.metro);
394
+		case 13: /* nmask */
395
+			if((gpv->item->r.flags&1024)==0)
396
+			{
397
+				gpv->item->r.nmask[0] = '\0';
398
+				snprintf(gpv->item->r.nmask, 8, "%hd", gpv->item->r.record.netmask);
399
+				gpv->item->r.flags |= 1024;
400
+			}
401
+			return pv_geoip2_get_strzval(msg, param, res,
402
+					gpv->item->r.nmask);
403
+		default: /* cc */
404
+			if(gpv->item->r.country.s==NULL)
405
+			{
406
+				if(gpv->item->r.flags&512)
407
+					return pv_get_null(msg, param, res);
408
+				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
409
+					"country","iso_code", NULL
410
+					) != MMDB_SUCCESS
411
+					&& MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
412
+						"registered_country","iso_code", NULL
413
+						) != MMDB_SUCCESS
414
+					)
415
+					return pv_get_null(msg, param, res);
416
+				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
417
+					gpv->item->r.country.s = (char *)entry_data.utf8_string;
418
+					gpv->item->r.country.len = entry_data.data_size;
419
+				}
420
+				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
421
+					"traits","is_anonymous_proxy", NULL) == MMDB_SUCCESS
422
+					&& entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_BOOLEAN
423
+					&& entry_data.boolean) {
424
+					gpv->item->r.country.s = "A1";
425
+					gpv->item->r.country.len = 2;
426
+				}
427
+				gpv->item->r.flags |= 512;
428
+			}
429
+			return pv_get_strval(msg, param, res, &gpv->item->r.country);
430
+	}
431
+}
432
+
433
+int geoip2_init_pv(char *path)
434
+{
435
+	int status = MMDB_open(path, MMDB_MODE_MMAP, &_handle_GeoIP);
436
+	
437
+	if(MMDB_SUCCESS != status)
438
+	{
439
+		LM_ERR("cannot open GeoIP database file at: %s\n", path);
440
+		return -1;
441
+	}
442
+	return 0;
443
+}
444
+
445
+void geoip2_destroy_list(void)
446
+{
447
+}
448
+
449
+void geoip2_destroy_pv(void)
450
+{
451
+	MMDB_close(&_handle_GeoIP);
452
+}
453
+
454
+void geoip2_pv_reset(str *name)
455
+{
456
+	sr_geoip2_record_t *gr = NULL;
457
+	
458
+	gr = sr_geoip2_get_record(name);
459
+
460
+	if(gr==NULL)
461
+		return;
462
+	memset(gr, 0, sizeof(struct _sr_geoip2_record));
463
+}
464
+
465
+int geoip2_update_pv(str *tomatch, str *name)
466
+{
467
+	sr_geoip2_record_t *gr = NULL;
468
+	int gai_error, mmdb_error;
469
+	
470
+	if(tomatch->len>255)
471
+	{
472
+		LM_DBG("target too long (max 255): %s\n", tomatch->s);
473
+		return -3;
474
+	}
475
+	
476
+	gr = sr_geoip2_get_record(name);
477
+	if(gr==NULL)
478
+	{
479
+		LM_DBG("container not found: %s\n", tomatch->s);
480
+		return - 4;
481
+	}