1
#include "source/extensions/geoip_providers/maxmind/config.h"
2

            
3
#include "envoy/extensions/geoip_providers/maxmind/v3/maxmind.pb.h"
4
#include "envoy/registry/registry.h"
5

            
6
#include "source/common/common/utility.h"
7
#include "source/common/protobuf/utility.h"
8
#include "source/extensions/geoip_providers/maxmind/geoip_provider.h"
9

            
10
namespace Envoy {
11
namespace Extensions {
12
namespace GeoipProviders {
13
namespace Maxmind {
14

            
15
using ConfigProto = envoy::extensions::geoip_providers::maxmind::v3::MaxMindConfig;
16

            
17
/**
18
 * A singleton that acts as a factory for generating and looking up GeoipProviders.
19
 * When given equivalent provider configs, the singleton returns pointers to the same
20
 * driver/provider. When given different configs, the singleton returns different provider
21
 * instances.
22
 */
23
class DriverSingleton : public Envoy::Singleton::Instance {
24
public:
25
  std::shared_ptr<GeoipProvider> get(std::shared_ptr<DriverSingleton> singleton,
26
                                     const ConfigProto& proto_config,
27
                                     const std::string& stat_prefix,
28
88
                                     Server::Configuration::FactoryContext& context) {
29
88
    std::shared_ptr<GeoipProvider> driver;
30
88
    const uint64_t key = MessageUtil::hash(proto_config);
31
88
    absl::MutexLock lock(mu_);
32
88
    auto it = drivers_.find(key);
33
88
    if (it != drivers_.end()) {
34
3
      driver = it->second.lock();
35
85
    } else {
36
85
      const auto& provider_config =
37
85
          std::make_shared<GeoipProviderConfig>(proto_config, stat_prefix, context.scope());
38
85
      driver = std::make_shared<GeoipProvider>(
39
85
          context.serverFactoryContext().mainThreadDispatcher(),
40
85
          context.serverFactoryContext().api(), singleton, provider_config);
41
85
      drivers_[key] = driver;
42
85
    }
43
88
    return driver;
44
88
  }
45

            
46
private:
47
  absl::Mutex mu_;
48
  // We keep weak_ptr here so the providers can be destroyed if the config is updated to stop using
49
  // that config of the provider. Each provider stores shared_ptrs to this singleton, which keeps
50
  // the singleton from being destroyed unless it's no longer keeping track of any providers. (The
51
  // singleton shared_ptr is *only* held by driver instances.)
52
  absl::flat_hash_map<uint64_t, std::weak_ptr<GeoipProvider>> drivers_ ABSL_GUARDED_BY(mu_);
53
};
54

            
55
SINGLETON_MANAGER_REGISTRATION(maxmind_geolocation_provider_singleton);
56

            
57
20
MaxmindProviderFactory::MaxmindProviderFactory() : FactoryBase("envoy.geoip_providers.maxmind") {}
58

            
59
DriverSharedPtr MaxmindProviderFactory::createGeoipProviderDriverTyped(
60
    const ConfigProto& proto_config, const std::string& stat_prefix,
61
88
    Server::Configuration::FactoryContext& context) {
62
88
  std::shared_ptr<DriverSingleton> drivers =
63
88
      context.serverFactoryContext().singletonManager().getTyped<DriverSingleton>(
64
88
          SINGLETON_MANAGER_REGISTERED_NAME(maxmind_geolocation_provider_singleton),
65
88
          [] { return std::make_shared<DriverSingleton>(); });
66
88
  return drivers->get(drivers, proto_config, stat_prefix, context);
67
88
}
68

            
69
/**
70
 * Static registration for the Maxmind provider. @see RegisterFactory.
71
 */
72
REGISTER_FACTORY(MaxmindProviderFactory, Geolocation::GeoipProviderFactory);
73

            
74
} // namespace Maxmind
75
} // namespace GeoipProviders
76
} // namespace Extensions
77
} // namespace Envoy