Search code examples
c++socketsopensslpoco

Identify state of socket in half-open connection using POCO Frame


I have a problem then I'm trying reconnect with server, using Poco underlying in my Proxy. In the end of connect sessions I recieve FIN,ACK package from server. Then TCP send ACK to answer server about recieving their FIN. So i have half-open connection. My socket is closed to read but not to send. After a few second of waiting, I send http request,

auto& requestStream = mSession->sendRequest(request);
Poco::StreamCopier::copyStream(request.stream(), requestStream);

auto& responseStream = mSession->receiveResponse(response);
Poco::StreamCopier::copyStream(responseStream, response.send());

TCP send FIN,ACK and send SYN to start another connect session so i recieve exception on SSL_Read().

One way to resolve that is identify state of socket using shutdown

if (SSL_get_shutdown(ssl) & SSL_RECEIVED_SHUTDOWN)
    reconnect();

but its not legal, bcs SSL* ssl is private field of SecureSocketImpl _impl that is private field of ServerSocketImpl too.

Have you ever encountered this problem?

This is screen of wireshark.


Solution

  • Ok, this problem wont be resolved until POCO pay attention to it. I suggest my way.

    In my case, server doesnt sent SSL_shutdown, so my socket is open.

    You should previously check that socket is empty and suppress this exception. After that u can check, that server has sent SSL_shutdown() before reconnection. Then u should use reconnect to recover your session.

    Here is description how to make hack to check the state of your socket.

    class HttpsClientSession : public HTTPSClientSession {
    
    public:
        using Super::HTTPSClientSession;
    
        ostream& sendRequest(HTTPRequest& request) override {
                if (connected() && socket().poll(Poco::Timespan(0), Socket::SELECT_READ)) {
                        try {
                                peek();
                        } catch (const SSLConnectionUnexpectedlyClosedException&) {
                                reconnect();
                        }
    
                        auto sock = static_cast<SecureStreamSocketImpl*>(socket().impl());
                        auto ssl = PRIVATE_ACCESS(PRIVATE_ACCESS(*sock, _impl), _pSSL);
    
                        if (SSL_get_shutdown(ssl) & SSL_RECEIVED_SHUTDOWN)
                                reconnect();
                }
    
                return HTTPSClientSession::sendRequest(request);
        }
    };
    

    ¯\_(ツ)_/¯