summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRoland Reichwein <mail@reichwein.it>2020-05-21 18:00:25 +0200
committerRoland Reichwein <mail@reichwein.it>2020-05-21 18:00:25 +0200
commit4b34a4d950f762b5d020d5ac4d3354836833039c (patch)
tree6753cadbc2d4d956d18b045207278562bc9a56ee
parent72a0f20c07ecf321a4d15f5afe8938eb2b509668 (diff)
FCGI: Fix connection handling on broken pipe: Reopen new socket
-rw-r--r--plugins/fcgi/fcgi.cpp10
-rw-r--r--plugins/fcgi/socket.cpp49
-rw-r--r--plugins/fcgi/socket.h6
3 files changed, 57 insertions, 8 deletions
diff --git a/plugins/fcgi/fcgi.cpp b/plugins/fcgi/fcgi.cpp
index 5a7ce65..7748845 100644
--- a/plugins/fcgi/fcgi.cpp
+++ b/plugins/fcgi/fcgi.cpp
@@ -357,7 +357,7 @@ std::string fcgi_plugin::fcgiQuery(FCGIContext& context)
std::lock_guard<std::mutex> socket_lock{socket->getMutex()};
if (!socket->is_open()) {
- //std::cout << "FCGI: Opening new socket" << std::endl;
+ std::cout << "FCGI: Opening new socket to " << app_addr << std::endl;
socket->open();
opening = true;
@@ -402,7 +402,12 @@ std::string fcgi_plugin::fcgiQuery(FCGIContext& context)
std::cerr << "Warning: Not all bytes written" << std::endl;
} catch (const fcgi_eof_error&) {
std::cerr << "FCGI Error: EOF on write" << std::endl; // seems to be ok here
+ m_sockets.erase(app_addr); // force new socket next time
return HttpStatus("500", "FCGI connection: EOF on write", context.SetResponseHeader);
+ } catch (const fcgi_broken_pipe_error&) {
+ std::cerr << "FCGI Error: Broken pipe on write" << std::endl; // seems to be ok here
+ m_sockets.erase(app_addr); // force new socket next time
+ return HttpStatus("500", "FCGI connection: Broken pipe on write", context.SetResponseHeader);
}
#if 0
@@ -418,7 +423,8 @@ std::string fcgi_plugin::fcgiQuery(FCGIContext& context)
try {
socket->read(inbuf);
} catch (const fcgi_eof_error&) {
- std::cerr << "FCGI Warning: Early EOF" << std::endl; // seems to be ok here
+ std::cerr << "FCGI Warning: Early EOF from application server. Break." << std::endl; // seems to be ok here
+ m_sockets.erase(app_addr); // force new socket next time
ended = true;
//return HttpStatus("500", "FCGI connection: EOF on read", context.SetResponseHeader);
}
diff --git a/plugins/fcgi/socket.cpp b/plugins/fcgi/socket.cpp
index badcec6..82bb06b 100644
--- a/plugins/fcgi/socket.cpp
+++ b/plugins/fcgi/socket.cpp
@@ -81,11 +81,44 @@ void TCPSocket::open()
bool TCPSocket::is_open()
{
- return m_socket.is_open();
+ if (m_socket.is_open()) {
+ std::vector<char> inbuf;
+
+ int error;
+ socklen_t len = sizeof (error);
+ int retval {getsockopt(m_socket.native_handle(), SOL_SOCKET, SO_ERROR, &error, &len)};
+
+ if (retval) {
+ std::cerr << "FCGI Error: getsockopt() error in is_open(): " << strerror(errno) << std::endl;
+ try {
+ // for graceful shutdown, according to
+ // https://www.boost.org/doc/libs/1_66_0/doc/html/boost_asio/reference/basic_stream_socket/close/overload1.html
+ m_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
+ m_socket.close(); // correct state
+ } catch (...) {
+ std::cerr << "Error on shutdown/close" << std::endl;
+ }
+ return false;
+ }
+
+ if (error != 0) {
+ try {
+ m_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
+ m_socket.close(); // correct state
+ } catch (...) {
+ std::cerr << "Error on shutdown/close" << std::endl;
+ }
+ return false;
+ }
+
+ return true;
+ } else
+ return false;
}
void TCPSocket::close()
{
+ m_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
m_socket.close();
}
@@ -96,6 +129,8 @@ size_t TCPSocket::write(const std::vector<char>& data)
} catch (const boost::system::system_error& ex) {
if (ex.code() == boost::asio::error::eof) {
throw fcgi_eof_error("EOF on write");
+ } else if (ex.code() == boost::asio::error::broken_pipe) {
+ throw fcgi_broken_pipe_error("Application server connection broken");
} else
throw std::runtime_error("FCGI Error: Unknown boost asio exception on write: "s + ex.what());
} catch (const std::exception& ex) {
@@ -108,12 +143,12 @@ size_t TCPSocket::read(std::vector<char>& data)
try {
size_t result{0};
- while (m_socket.available()) {
+ do {
std::vector<char> inbuf_part(1024);
size_t got { m_socket.read_some(boost::asio::buffer(inbuf_part))};
data.insert(data.end(), inbuf_part.begin(), inbuf_part.begin() + got);
result += got;
- }
+ } while (m_socket.available());
return result;
@@ -165,6 +200,8 @@ size_t FileSocket::write(const std::vector<char>& data)
} catch (const boost::system::system_error& ex) {
if (ex.code() == boost::asio::error::eof) {
throw fcgi_eof_error("EOF on write");
+ } else if (ex.code() == boost::asio::error::broken_pipe) {
+ throw fcgi_broken_pipe_error("Application server connection broken");
} else
throw std::runtime_error("FCGI Error: Unknown boost asio exception on write: "s + ex.what());
} catch (const std::exception& ex) {
@@ -176,13 +213,13 @@ size_t FileSocket::read(std::vector<char>& data)
{
try {
size_t result{0};
-
- while (m_socket.available()) {
+
+ do {
std::vector<char> inbuf_part(1024);
size_t got { m_socket.read_some(boost::asio::buffer(inbuf_part))};
data.insert(data.end(), inbuf_part.begin(), inbuf_part.begin() + got);
result += got;
- }
+ } while (m_socket.available());
return result;
} catch (const boost::system::system_error& ex) {
diff --git a/plugins/fcgi/socket.h b/plugins/fcgi/socket.h
index 8fb5610..272b844 100644
--- a/plugins/fcgi/socket.h
+++ b/plugins/fcgi/socket.h
@@ -15,6 +15,12 @@ public:
fcgi_eof_error(const std::string& what_arg): std::runtime_error(what_arg) {}
};
+class fcgi_broken_pipe_error: public std::runtime_error
+{
+public:
+ fcgi_broken_pipe_error(const std::string& what_arg): std::runtime_error(what_arg) {}
+};
+
class Socket
{
std::mutex m_mutex; // guard socket use in different threads