2424#include < unistd.h>
2525#include < arpa/inet.h>
2626#include < cctype>
27+ #include < mutex>
2728
2829#include " ts/ts.h"
2930
3031#include " conditions_geo.h"
3132
3233#include < GeoIP.h>
3334
34- GeoIP *gGeoIP [NUM_DB_TYPES];
35+ struct GeoIPHandleSet {
36+ GeoIP *dbs[NUM_DB_TYPES] = {};
37+ };
3538
36- void
39+ static std::mutex gGeoIPCacheMutex ;
40+ static GeoIPHandleSet *gGeoIPHandleSet = nullptr ;
41+
42+ void *
3743GeoIPConditionGeo::initLibrary (const std::string &)
3844{
45+ std::lock_guard<std::mutex> lock (gGeoIPCacheMutex );
46+
47+ if (gGeoIPHandleSet != nullptr ) {
48+ return gGeoIPHandleSet ;
49+ }
50+
51+ gGeoIPHandleSet = new GeoIPHandleSet;
52+
3953 GeoIPDBTypes dbs[] = {GEOIP_COUNTRY_EDITION, GEOIP_COUNTRY_EDITION_V6, GEOIP_ASNUM_EDITION, GEOIP_ASNUM_EDITION_V6};
4054
4155 for (auto &db : dbs) {
42- if (!gGeoIP [db] && GeoIP_db_avail (db)) {
43- // GEOIP_STANDARD seems to break threaded apps...
44- gGeoIP [db] = GeoIP_open_type (db, GEOIP_MMAP_CACHE);
56+ if (!gGeoIPHandleSet ->dbs [db] && GeoIP_db_avail (db)) {
57+ gGeoIPHandleSet ->dbs [db] = GeoIP_open_type (db, GEOIP_MMAP_CACHE);
4558
46- char *db_info = GeoIP_database_info (gGeoIP [db]);
59+ char *db_info = GeoIP_database_info (gGeoIPHandleSet -> dbs [db]);
4760 Dbg (pi_dbg_ctl, " initialized GeoIP-DB[%d] %s" , db, db_info);
4861 free (db_info);
4962 }
5063 }
64+
65+ return gGeoIPHandleSet ;
5166}
5267
5368std::string
54- GeoIPConditionGeo::get_geo_string (const sockaddr *addr) const
69+ GeoIPConditionGeo::get_geo_string (const sockaddr *addr, void *geo_handle ) const
5570{
5671 std::string ret = " (unknown)" ;
5772 int v = 4 ;
5873
59- if (addr) {
74+ auto *handle = static_cast <GeoIPHandleSet *>(geo_handle);
75+
76+ if (addr && handle) {
6077 switch (_geo_qual) {
6178 // Country database
6279 case GEO_QUAL_COUNTRY:
6380 switch (addr->sa_family ) {
6481 case AF_INET:
65- if (gGeoIP [GEOIP_COUNTRY_EDITION]) {
82+ if (handle-> dbs [GEOIP_COUNTRY_EDITION]) {
6683 uint32_t ip = ntohl (reinterpret_cast <const struct sockaddr_in *>(addr)->sin_addr .s_addr );
6784
68- ret = GeoIP_country_code_by_ipnum (gGeoIP [GEOIP_COUNTRY_EDITION], ip);
85+ ret = GeoIP_country_code_by_ipnum (handle-> dbs [GEOIP_COUNTRY_EDITION], ip);
6986 }
7087 break ;
7188 case AF_INET6: {
72- if (gGeoIP [GEOIP_COUNTRY_EDITION_V6]) {
89+ if (handle-> dbs [GEOIP_COUNTRY_EDITION_V6]) {
7390 geoipv6_t ip = reinterpret_cast <const struct sockaddr_in6 *>(addr)->sin6_addr ;
7491
7592 v = 6 ;
76- ret = GeoIP_country_code_by_ipnum_v6 (gGeoIP [GEOIP_COUNTRY_EDITION_V6], ip);
93+ ret = GeoIP_country_code_by_ipnum_v6 (handle-> dbs [GEOIP_COUNTRY_EDITION_V6], ip);
7794 }
7895 } break ;
7996 default :
@@ -86,18 +103,18 @@ GeoIPConditionGeo::get_geo_string(const sockaddr *addr) const
86103 case GEO_QUAL_ASN_NAME:
87104 switch (addr->sa_family ) {
88105 case AF_INET:
89- if (gGeoIP [GEOIP_ASNUM_EDITION]) {
106+ if (handle-> dbs [GEOIP_ASNUM_EDITION]) {
90107 uint32_t ip = ntohl (reinterpret_cast <const struct sockaddr_in *>(addr)->sin_addr .s_addr );
91108
92- ret = GeoIP_name_by_ipnum (gGeoIP [GEOIP_ASNUM_EDITION], ip);
109+ ret = GeoIP_name_by_ipnum (handle-> dbs [GEOIP_ASNUM_EDITION], ip);
93110 }
94111 break ;
95112 case AF_INET6: {
96- if (gGeoIP [GEOIP_ASNUM_EDITION_V6]) {
113+ if (handle-> dbs [GEOIP_ASNUM_EDITION_V6]) {
97114 geoipv6_t ip = reinterpret_cast <const struct sockaddr_in6 *>(addr)->sin6_addr ;
98115
99116 v = 6 ;
100- ret = GeoIP_name_by_ipnum_v6 (gGeoIP [GEOIP_ASNUM_EDITION_V6], ip);
117+ ret = GeoIP_name_by_ipnum_v6 (handle-> dbs [GEOIP_ASNUM_EDITION_V6], ip);
101118 }
102119 } break ;
103120 default :
@@ -114,12 +131,14 @@ GeoIPConditionGeo::get_geo_string(const sockaddr *addr) const
114131}
115132
116133int64_t
117- GeoIPConditionGeo::get_geo_int (const sockaddr *addr) const
134+ GeoIPConditionGeo::get_geo_int (const sockaddr *addr, void *geo_handle ) const
118135{
119136 int64_t ret = -1 ;
120137 int v = 4 ;
121138
122- if (!addr) {
139+ auto *handle = static_cast <GeoIPHandleSet *>(geo_handle);
140+
141+ if (!addr || !handle) {
123142 return 0 ;
124143 }
125144
@@ -128,18 +147,18 @@ GeoIPConditionGeo::get_geo_int(const sockaddr *addr) const
128147 case GEO_QUAL_COUNTRY_ISO:
129148 switch (addr->sa_family ) {
130149 case AF_INET:
131- if (gGeoIP [GEOIP_COUNTRY_EDITION]) {
150+ if (handle-> dbs [GEOIP_COUNTRY_EDITION]) {
132151 uint32_t ip = ntohl (reinterpret_cast <const struct sockaddr_in *>(addr)->sin_addr .s_addr );
133152
134- ret = GeoIP_id_by_ipnum (gGeoIP [GEOIP_COUNTRY_EDITION], ip);
153+ ret = GeoIP_id_by_ipnum (handle-> dbs [GEOIP_COUNTRY_EDITION], ip);
135154 }
136155 break ;
137156 case AF_INET6: {
138- if (gGeoIP [GEOIP_COUNTRY_EDITION_V6]) {
157+ if (handle-> dbs [GEOIP_COUNTRY_EDITION_V6]) {
139158 geoipv6_t ip = reinterpret_cast <const struct sockaddr_in6 *>(addr)->sin6_addr ;
140159
141160 v = 6 ;
142- ret = GeoIP_id_by_ipnum_v6 (gGeoIP [GEOIP_COUNTRY_EDITION_V6], ip);
161+ ret = GeoIP_id_by_ipnum_v6 (handle-> dbs [GEOIP_COUNTRY_EDITION_V6], ip);
143162 }
144163 } break ;
145164 default :
@@ -153,18 +172,18 @@ GeoIPConditionGeo::get_geo_int(const sockaddr *addr) const
153172
154173 switch (addr->sa_family ) {
155174 case AF_INET:
156- if (gGeoIP [GEOIP_ASNUM_EDITION]) {
175+ if (handle-> dbs [GEOIP_ASNUM_EDITION]) {
157176 uint32_t ip = ntohl (reinterpret_cast <const struct sockaddr_in *>(addr)->sin_addr .s_addr );
158177
159- asn_name = GeoIP_name_by_ipnum (gGeoIP [GEOIP_ASNUM_EDITION], ip);
178+ asn_name = GeoIP_name_by_ipnum (handle-> dbs [GEOIP_ASNUM_EDITION], ip);
160179 }
161180 break ;
162181 case AF_INET6:
163- if (gGeoIP [GEOIP_ASNUM_EDITION_V6]) {
182+ if (handle-> dbs [GEOIP_ASNUM_EDITION_V6]) {
164183 geoipv6_t ip = reinterpret_cast <const struct sockaddr_in6 *>(addr)->sin6_addr ;
165184
166185 v = 6 ;
167- asn_name = GeoIP_name_by_ipnum_v6 (gGeoIP [GEOIP_ASNUM_EDITION_V6], ip);
186+ asn_name = GeoIP_name_by_ipnum_v6 (handle-> dbs [GEOIP_ASNUM_EDITION_V6], ip);
168187 }
169188 break ;
170189 }
0 commit comments