1
#include "source/exe/main_common.h"
2

            
3
#include <fstream>
4
#include <iostream>
5
#include <memory>
6
#include <new>
7

            
8
#include "envoy/config/listener/v3/listener.pb.h"
9

            
10
#include "source/common/common/compiler_requirements.h"
11
#include "source/common/common/logger.h"
12
#include "source/common/common/perf_annotation.h"
13
#include "source/common/common/thread.h"
14
#include "source/common/network/utility.h"
15
#include "source/common/stats/thread_local_store.h"
16
#include "source/exe/platform_impl.h"
17
#include "source/server/config_validation/server.h"
18
#include "source/server/drain_manager_impl.h"
19
#include "source/server/hot_restart_nop_impl.h"
20
#include "source/server/instance_impl.h"
21
#include "source/server/listener_hooks.h"
22
#include "source/server/options_impl_base.h"
23

            
24
#include "absl/debugging/symbolize.h"
25
#include "absl/strings/str_split.h"
26

            
27
#ifdef ENVOY_HOT_RESTART
28
#include "source/server/hot_restart_impl.h"
29
#endif
30

            
31
namespace Envoy {
32

            
33
43
StrippedMainBase::CreateInstanceFunction createFunction() {
34
43
  return
35
43
      [](Init::Manager& init_manager, const Server::Options& options,
36
43
         Event::TimeSystem& time_system, ListenerHooks& hooks, Server::HotRestart& restarter,
37
43
         Stats::StoreRoot& store, Thread::BasicLockable& access_log_lock,
38
43
         Server::ComponentFactory& component_factory, Random::RandomGeneratorPtr&& random_generator,
39
43
         ThreadLocal::Instance& tls, Thread::ThreadFactory& thread_factory,
40
43
         Filesystem::Instance& file_system, std::unique_ptr<ProcessContext> process_context,
41
43
         Buffer::WatermarkFactorySharedPtr watermark_factory) {
42
41
        auto local_address = Network::Utility::getLocalAddress(options.localAddressIpVersion());
43
41
        auto server = std::make_unique<Server::InstanceImpl>(
44
41
            init_manager, options, time_system, hooks, restarter, store, access_log_lock,
45
41
            std::move(random_generator), tls, thread_factory, file_system,
46
41
            std::move(process_context), watermark_factory);
47
41
        server->initialize(local_address, component_factory);
48
41
        return server;
49
41
      };
50
43
}
51

            
52
MainCommonBase::MainCommonBase(const Server::Options& options, Event::TimeSystem& time_system,
53
                               ListenerHooks& listener_hooks,
54
                               Server::ComponentFactory& component_factory,
55
                               std::unique_ptr<Server::Platform> platform_impl,
56
                               std::unique_ptr<Random::RandomGenerator>&& random_generator,
57
                               std::unique_ptr<ProcessContext> process_context)
58
44
    : StrippedMainBase(options, component_factory, std::move(platform_impl), *random_generator)
59
#ifdef ENVOY_ADMIN_FUNCTIONALITY
60
      ,
61
44
      shared_response_set_(std::make_shared<AdminResponse::PtrSet>())
62
#endif
63
44
{
64
44
  if (options.mode() == Server::Mode::Serve) {
65
    // Provide consistent behavior for out-of-memory, regardless of whether it occurs in a
66
    // try/catch block or not.
67
39
    std::set_new_handler([]() { PANIC("out of memory"); });
68
39
  }
69

            
70
44
  logging_context_ = std::make_unique<Logger::Context>(
71
44
      options_.logLevel(), options_.logFormat(), restarter_->logLock(), options_.logFormatEscaped(),
72
44
      options_.mode() == Server::Mode::Validate ? false : options_.enableFineGrainLogging());
73
44
  init(time_system, listener_hooks, std::move(random_generator), std::move(process_context),
74
44
       createFunction());
75
44
}
76

            
77
33
bool MainCommonBase::run() {
78
  // Avoid returning from inside switch cases to minimize uncovered lines
79
  // while avoiding gcc warnings by hitting the final return.
80
33
  bool ret = false;
81

            
82
33
  switch (options_.mode()) {
83
29
  case Server::Mode::Serve:
84
29
    runServer();
85
29
#ifdef ENVOY_ADMIN_FUNCTIONALITY
86
29
    shared_response_set_->terminateAdminRequests();
87
29
#endif
88
29
    ret = true;
89
29
    break;
90
2
  case Server::Mode::Validate:
91
2
    ret = Server::validateConfig(
92
2
        options_, Network::Utility::getLocalAddress(options_.localAddressIpVersion()),
93
2
        component_factory_, platform_impl_->threadFactory(), platform_impl_->fileSystem(),
94
2
        process_context_ ? ProcessContextOptRef(std::ref(*process_context_)) : absl::nullopt);
95
2
    break;
96
2
  case Server::Mode::InitOnly:
97
2
    PERF_DUMP();
98
2
    ret = true;
99
2
    break;
100
33
  }
101
33
  return ret;
102
33
}
103

            
104
#ifdef ENVOY_ADMIN_FUNCTIONALITY
105

            
106
// This request variant buffers the entire response in one string. New uses
107
// should opt for the streaming version below, where an AdminResponse object
108
// is created and used to stream data with flow-control.
109
void MainCommonBase::adminRequest(absl::string_view path_and_query, absl::string_view method,
110
31
                                  const AdminRequestFn& handler) {
111
31
  std::string path_and_query_buf = std::string(path_and_query);
112
31
  std::string method_buf = std::string(method);
113
31
  server_->dispatcher().post([this, path_and_query_buf, method_buf, handler]() {
114
30
    auto response_headers = Http::ResponseHeaderMapImpl::create();
115
30
    std::string body;
116
30
    if (server_->admin()) {
117
30
      server_->admin()->request(path_and_query_buf, method_buf, *response_headers, body);
118
30
    }
119
30
    handler(*response_headers, body);
120
30
  });
121
31
}
122

            
123
AdminResponseSharedPtr MainCommonBase::adminRequest(absl::string_view path_and_query,
124
21
                                                    absl::string_view method) {
125
21
  auto response =
126
21
      std::make_shared<AdminResponse>(*server(), path_and_query, method, shared_response_set_);
127
21
  shared_response_set_->attachResponse(response.get());
128
21
  return response;
129
21
}
130
#endif
131

            
132
MainCommon::MainCommon(const std::vector<std::string>& args)
133
1
    : options_(args, &MainCommon::hotRestartVersion, spdlog::level::info),
134
1
      base_(options_, real_time_system_, default_listener_hooks_, prod_component_factory_,
135
1
            std::make_unique<PlatformImpl>(), std::make_unique<Random::RandomGeneratorImpl>(),
136
1
            nullptr) {}
137

            
138
MainCommon::MainCommon(int argc, const char* const* argv)
139
44
    : options_(argc, argv, &MainCommon::hotRestartVersion, spdlog::level::info),
140
44
      base_(options_, real_time_system_, default_listener_hooks_, prod_component_factory_,
141
44
            std::make_unique<PlatformImpl>(), std::make_unique<Random::RandomGeneratorImpl>(),
142
44
            nullptr) {}
143

            
144
std::string MainCommon::hotRestartVersion(bool hot_restart_enabled) {
145
#ifdef ENVOY_HOT_RESTART
146
  if (hot_restart_enabled) {
147
    return Server::HotRestartImpl::hotRestartVersion();
148
  }
149
#else
150
  UNREFERENCED_PARAMETER(hot_restart_enabled);
151
#endif
152
  return "disabled";
153
}
154

            
155
9
int MainCommon::main(int argc, char** argv, PostServerHook hook) {
156
9
#ifndef __APPLE__
157
  // absl::Symbolize mostly works without this, but this improves corner case
158
  // handling, such as running in a chroot jail.
159
9
  absl::InitializeSymbolizer(argv[0]);
160
9
#endif
161
9
  Thread::MainThread main_thread;
162
9
  std::unique_ptr<Envoy::MainCommon> main_common;
163

            
164
  // Initialize the server's main context under a try/catch loop and simply return EXIT_FAILURE
165
  // as needed. Whatever code in the initialization path that fails is expected to log an error
166
  // message so the user can diagnose.
167
9
  TRY_ASSERT_MAIN_THREAD {
168
9
    main_common = std::make_unique<Envoy::MainCommon>(argc, argv);
169
9
    Envoy::Server::Instance* server = main_common->server();
170
9
    if (server != nullptr && hook != nullptr) {
171
1
      hook(*server);
172
1
    }
173
9
  }
174
9
  END_TRY
175
9
  catch (const Envoy::NoServingException& e) {
176
    return EXIT_SUCCESS;
177
  }
178
9
  catch (const Envoy::MalformedArgvException& e) {
179
6
    std::cerr << e.what() << std::endl;
180
6
    return EXIT_FAILURE;
181
6
  }
182
9
  catch (const Envoy::EnvoyException& e) {
183
1
    std::cerr << e.what() << std::endl;
184
1
    return EXIT_FAILURE;
185
1
  }
186

            
187
  // Run the server listener loop outside try/catch blocks, so that unexpected exceptions
188
  // show up as a core-dumps for easier diagnostics.
189
2
  return main_common->run() ? EXIT_SUCCESS : EXIT_FAILURE;
190
9
}
191

            
192
} // namespace Envoy