summaryrefslogtreecommitdiffhomepage
path: root/plugins/fcgi
diff options
context:
space:
mode:
authorRoland Reichwein <mail@reichwein.it>2020-05-03 22:52:45 +0200
committerRoland Reichwein <mail@reichwein.it>2020-05-03 22:52:45 +0200
commit1cc484b25547e349177cf652f62021b802f48655 (patch)
tree9f07ef0a57aa145943df8e2c200b48f9b9a48a32 /plugins/fcgi
parentf60f8e469cf8c2aff2cf62e42a46ad806e663d41 (diff)
Fixed TCP keepalive (workaround)
Diffstat (limited to 'plugins/fcgi')
-rw-r--r--plugins/fcgi/fcgi.cpp105
-rw-r--r--plugins/fcgi/fcgi.h2
2 files changed, 72 insertions, 35 deletions
diff --git a/plugins/fcgi/fcgi.cpp b/plugins/fcgi/fcgi.cpp
index 416ca24..464ba75 100644
--- a/plugins/fcgi/fcgi.cpp
+++ b/plugins/fcgi/fcgi.cpp
@@ -344,59 +344,94 @@ std::string fcgi_plugin::fcgiQuery(FCGIContext& context)
std::unordered_map<std::string, std::string> app_values; // will be read by FCGI_GET_VALUES
size_t pos { app_addr.find(':') };
- if (pos != app_addr.npos) { // host:port
+ if (pos != app_addr.npos) { // tcp socket: host:port
auto endpoints{m_resolver.resolve(app_addr.substr(0, pos), app_addr.substr(pos + 1))};
bool opening{false};
std::lock_guard<std::mutex> socket_lock{m_socket_mutex};
- if (!m_socket.is_open()) {
+ auto it {m_sockets.find(app_addr)};
+
+ std::pair<std::unordered_map<std::string, boost::asio::ip::tcp::socket>::iterator, bool> it2{m_sockets.end(), false};
+ if (it == m_sockets.end())
+ it2 = m_sockets.emplace(app_addr, m_io_context); // add new element if necessary
+
+ boost::asio::ip::tcp::socket& socket { it2.second ? it2.first->second : it->second }; // use just added element or previously found one
+
+ socket.close(); // TODO: Bug workaround: Keeping TCP socket open doesn't work for now
+
+ if (!socket.is_open()) {
std::cout << "FCGI: Opening new socket" << std::endl;
- boost::asio::connect(m_socket, endpoints);
+
+ boost::asio::connect(socket, endpoints);
+
+ boost::asio::socket_base::keep_alive keepAlive(true);
+ socket.set_option(keepAlive);
+
+ struct timeval tv;
+ tv.tv_sec = 0; // infinite
+ tv.tv_usec = 0;
+ if (setsockopt(socket.native_handle(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)))
+ std::cerr << "FCGI Error: SO_RCVTIMEO" << std::endl;
+
+ if (setsockopt(socket.native_handle(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)))
+ std::cerr << "FCGI Error: SO_SNDTIMEO" << std::endl;
+
+ int val{1};
+ if (setsockopt(socket.native_handle(), SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)))
+ std::cerr << "FCGI Error: SO_KEEPALIVE" << std::endl;
+
opening = true;
}
- if (!m_socket.is_open()) {
+ if (!socket.is_open()) {
return HttpStatus("500", "FCGI connection", context.SetResponseHeader);
}
- if (opening) {
- FCGI_Record get_values{FCGI_GET_VALUES, 0, system_config_bytes};
- if (m_socket.write_some(boost::asio::buffer(get_values.getBuffer())) != get_values.getBuffer().size())
- std::cerr << "Warning: Not all bytes written 1" << std::endl;
- }
-
FCGI_ID_Guard id_guard(m_fcgi_id);
uint16_t id {id_guard.getID()};
- FCGI_Record begin_request{FCGI_BEGIN_REQUEST, id, FCGI_RESPONDER, FCGI_KEEP_CONN};
- if (m_socket.write_some(boost::asio::buffer(begin_request.getBuffer())) != begin_request.getBuffer().size())
- std::cerr << "Warning: Not all bytes written 3" << std::endl;
+ try {
+ if (opening) {
+ FCGI_Record get_values{FCGI_GET_VALUES, 0, system_config_bytes};
+ if (socket.write_some(boost::asio::buffer(get_values.getBuffer())) != get_values.getBuffer().size())
+ std::cerr << "Warning: Not all bytes written 1" << std::endl;
+ }
+
+ FCGI_Record begin_request{FCGI_BEGIN_REQUEST, id, FCGI_RESPONDER, FCGI_KEEP_CONN};
+ if (socket.write_some(boost::asio::buffer(begin_request.getBuffer())) != begin_request.getBuffer().size())
+ std::cerr << "Warning: Not all bytes written 3" << std::endl;
- FCGI_Record params{FCGI_PARAMS, id, env_bytes};
- if (m_socket.write_some(boost::asio::buffer(params.getBuffer())) != params.getBuffer().size())
- std::cerr << "Warning: Not all bytes written 4" << std::endl;
+ FCGI_Record params{FCGI_PARAMS, id, env_bytes};
+ if (socket.write_some(boost::asio::buffer(params.getBuffer())) != params.getBuffer().size())
+ std::cerr << "Warning: Not all bytes written 4" << std::endl;
- if (env_bytes.size()) {
- FCGI_Record params_end{FCGI_PARAMS, id, std::string{}};
- if (m_socket.write_some(boost::asio::buffer(params_end.getBuffer())) != params_end.getBuffer().size())
- std::cerr << "Warning: Not all bytes written 5" << std::endl;
- }
+ if (env_bytes.size()) {
+ FCGI_Record params_end{FCGI_PARAMS, id, std::string{}};
+ if (socket.write_some(boost::asio::buffer(params_end.getBuffer())) != params_end.getBuffer().size())
+ std::cerr << "Warning: Not all bytes written 5" << std::endl;
+ }
- std::string body {context.GetRequestParam("body")};
- FCGI_Record stdin_{FCGI_STDIN, id, body};
- if (m_socket.write_some(boost::asio::buffer(stdin_.getBuffer())) != stdin_.getBuffer().size())
- std::cerr << "Warning: Not all bytes written 6" << std::endl;
-
- if (body.size()) {
- FCGI_Record stdin_end{FCGI_STDIN, id, std::string{}};
- if (m_socket.write_some(boost::asio::buffer(stdin_end.getBuffer())) != stdin_end.getBuffer().size())
- std::cerr << "Warning: Not all bytes written 7" << std::endl;
+ std::string body {context.GetRequestParam("body")};
+ FCGI_Record stdin_{FCGI_STDIN, id, body};
+ if (socket.write_some(boost::asio::buffer(stdin_.getBuffer())) != stdin_.getBuffer().size())
+ std::cerr << "Warning: Not all bytes written 6" << std::endl;
+
+ if (body.size()) {
+ FCGI_Record stdin_end{FCGI_STDIN, id, std::string{}};
+ if (socket.write_some(boost::asio::buffer(stdin_end.getBuffer())) != stdin_end.getBuffer().size())
+ std::cerr << "Warning: Not all bytes written 7" << std::endl;
+ }
+ } catch (const boost::system::system_error& ex) {
+ if (ex.code() == boost::asio::error::eof) {
+ std::cerr << "FCGI Error: EOF on write" << std::endl; // seems to be ok here
+ return HttpStatus("500", "FCGI connection: EOF on write", context.SetResponseHeader);
+ }
}
#if 0
FCGI_Record data{FCGI_DATA, id, std::string{}};
- if (m_socket.write_some(boost::asio::buffer(data.getBuffer())) != data.getBuffer().size())
+ if (socket.write_some(boost::asio::buffer(data.getBuffer())) != data.getBuffer().size())
std::cerr << "Warning: Not all bytes written 8" << std::endl;
#endif
@@ -405,11 +440,13 @@ std::string fcgi_plugin::fcgiQuery(FCGIContext& context)
std::vector<char> inbuf_part(1024);
while (!ended) {
try {
- size_t got {m_socket.read_some(boost::asio::buffer(inbuf_part))};
+ size_t got {socket.read_some(boost::asio::buffer(inbuf_part))};
inbuf.insert(inbuf.end(), inbuf_part.begin(), inbuf_part.begin() + got);
} catch (const boost::system::system_error& ex) {
if (ex.code() == boost::asio::error::eof) {
//std::cerr << "FCGI Warning: Early EOF" << std::endl; // seems to be ok here
+ ended = true;
+ //return HttpStatus("500", "FCGI connection: EOF on read", context.SetResponseHeader);
} else {
std::cerr << "FCGI Warning: Expected EOF, got " << ex.code() << ", " << ex.what() << std::endl;
ended = true;
@@ -425,7 +462,7 @@ std::string fcgi_plugin::fcgiQuery(FCGIContext& context)
} else if (r.getType() == FCGI_STDOUT) {
output_data += r.getContent();
} else if (r.getType() == FCGI_STDERR) {
- std::cerr << "FCGI STDERR: " << r.getContent();
+ std::cerr << "FCGI STDERR: " << r.getContent() << std::endl;
} else if (r.getType() == FCGI_GET_VALUES_RESULT) {
FCGI_DecodeEnv(r.getContent(), app_values);
DumpAppValues(app_values);
@@ -437,6 +474,7 @@ std::string fcgi_plugin::fcgiQuery(FCGIContext& context)
}
}
}
+
} else if (fs::is_socket(fs::path{app_addr})) { // Unix domain socket
// TODO
std::cerr << "FCGI Error: Unix domain sockets not yet implemented." << std::endl;
@@ -496,7 +534,6 @@ std::string fcgi_plugin::name()
fcgi_plugin::fcgi_plugin()
: m_io_context()
, m_resolver(m_io_context)
- , m_socket(m_io_context)
{
//std::cout << "Plugin constructor" << std::endl;
}
diff --git a/plugins/fcgi/fcgi.h b/plugins/fcgi/fcgi.h
index b881aec..4f77719 100644
--- a/plugins/fcgi/fcgi.h
+++ b/plugins/fcgi/fcgi.h
@@ -62,7 +62,7 @@ class fcgi_plugin: public webserver_plugin_interface
boost::asio::ip::tcp::resolver m_resolver;
std::mutex m_socket_mutex; // guard m_socket use in different threads
- boost::asio::ip::tcp::socket m_socket;
+ std::unordered_map<std::string, boost::asio::ip::tcp::socket> m_sockets;
public:
fcgi_plugin();