-
Notifications
You must be signed in to change notification settings - Fork 9k
Expand file tree
/
Copy pathcreateServer.cpp
More file actions
126 lines (112 loc) · 4.68 KB
/
Copy pathcreateServer.cpp
File metadata and controls
126 lines (112 loc) · 4.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include <Server/createServer.h>
#include <Server/ProtocolServerAdapter.h>
#include <Common/CurrentThread.h>
#include <Common/ErrorCodes.h>
#include <Common/Exception.h>
#include <Poco/Util/AbstractConfiguration.h>
namespace DB
{
namespace ErrorCodes
{
extern const int NETWORK_ERROR;
}
bool createServer(
const Poco::Util::AbstractConfiguration & config,
const std::string & listen_host,
const char * port_name,
bool listen_try,
bool start_server,
std::vector<ProtocolServerAdapter> & servers,
CreateServerFunc && func,
LoggerRawPtr log)
{
/// For testing purposes, user may omit tcp_port or http_port or https_port in configuration file.
if (config.getString(port_name, "").empty())
return false;
/// If we already have an active server for this listen_host/port_name, don't create it again.
for (const auto & server : servers)
{
if (!server.isStopping() && server.getListenHost() == listen_host && server.getPortName() == port_name)
return false;
}
auto port = config.getInt(port_name);
bool binds_on_start = false;
try
{
servers.push_back(func(static_cast<UInt16>(port)));
binds_on_start = servers.back().bindsOnStart();
try
{
if (start_server)
{
servers.back().start();
LOG_INFO(log, "Listening for {}", servers.back().getDescription());
}
return true;
}
catch (...)
{
/// Roll back the just-pushed adapter so its bound socket is released
/// and a half-initialized listener does not linger in `servers`. We must
/// catch all exception types — not only `Poco::Exception` — so the outer
/// `Poco::Exception` handler below still wraps `Poco`-class errors into
/// `NETWORK_ERROR` (or logs them when `listen_try`) while non-`Poco`
/// exceptions propagate to the caller after the rollback.
servers.pop_back();
throw;
}
}
catch (const Poco::Exception &)
{
/// Delayed-bind protocols can fail their `start` operation before attempting a bind,
/// for example while loading TLS credentials. `listen_try` applies only to unavailable
/// listen addresses, so preserve these configuration errors for callers such as
/// `SYSTEM START LISTEN`.
if (start_server && binds_on_start && getCurrentExceptionCode() != ErrorCodes::NETWORK_ERROR)
throw;
if (listen_try)
{
LOG_WARNING(log, "Listen [{}]:{} failed: {}. If it is an IPv6 or IPv4 address and your host has disabled IPv6 or IPv4, "
"then consider to "
"specify not disabled IPv4 or IPv6 address to listen in <listen_host> element of configuration "
"file. Example for disabled IPv6: <listen_host>0.0.0.0</listen_host> ."
" Example for disabled IPv4: <listen_host>::</listen_host>",
listen_host, port, getCurrentExceptionMessage(false));
}
else
{
throw Exception(ErrorCodes::NETWORK_ERROR, "Listen [{}]:{} failed: {}", listen_host, port, getCurrentExceptionMessage(false));
}
}
return false;
}
void startServers(std::vector<ProtocolServerAdapter> & servers, bool listen_try, LoggerRawPtr log)
{
for (auto it = servers.begin(); it != servers.end();)
{
try
{
it->start();
LOG_INFO(log, "Listening for {}", it->getDescription());
++it;
}
catch (const Poco::Exception &)
{
/// A protocol that binds when its server is created has already passed the `listen_try`
/// check in `createServer`, so a failure here is not a listen failure and must not be
/// swallowed.
if (!it->bindsOnStart() || getCurrentExceptionCode() != ErrorCodes::NETWORK_ERROR)
throw;
if (!listen_try)
throw Exception(ErrorCodes::NETWORK_ERROR, "Failed to listen for {}: {}",
it->getDescription(), getCurrentExceptionMessage(false));
LOG_WARNING(log, "Failed to listen for {}: {}. If it is an IPv6 or IPv4 address and your host has disabled "
"IPv6 or IPv4, then consider to specify not disabled IPv4 or IPv6 address to listen in <listen_host> "
"element of configuration file. Example for disabled IPv6: <listen_host>0.0.0.0</listen_host> ."
" Example for disabled IPv4: <listen_host>::</listen_host>",
it->getDescription(), getCurrentExceptionMessage(false));
it = servers.erase(it);
}
}
}
}