diff options
author | Roland Reichwein <mail@reichwein.it> | 2020-05-03 22:52:45 +0200 |
---|---|---|
committer | Roland Reichwein <mail@reichwein.it> | 2020-05-03 22:52:45 +0200 |
commit | 1cc484b25547e349177cf652f62021b802f48655 (patch) | |
tree | 9f07ef0a57aa145943df8e2c200b48f9b9a48a32 /plugins/fcgi/fcgi.cpp | |
parent | f60f8e469cf8c2aff2cf62e42a46ad806e663d41 (diff) |
Fixed TCP keepalive (workaround)
Diffstat (limited to 'plugins/fcgi/fcgi.cpp')
-rw-r--r-- | plugins/fcgi/fcgi.cpp | 105 |
1 files changed, 71 insertions, 34 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; } |