Commit a375a520 authored by jan.koester's avatar jan.koester
Browse files

tcp timeout fix

parent a506797c
Loading
Loading
Loading
Loading
+34 −5
Original line number Diff line number Diff line
@@ -218,8 +218,10 @@ netplus::TlsSessionCache& libhttppp::HttpClient::tlsSessionCache() {
    return cache;
}

libhttppp::HttpClient::HttpClient(const HttpUrl& desturl, int vers)
libhttppp::HttpClient::HttpClient(const HttpUrl& desturl, int vers, int timeoutSec)
: _url(desturl), _vers(vers){
    _recvTimeoutSec = timeoutSec;
    _sendTimeoutSec = timeoutSec;
    try {
      if(vers == 3) {
        if (!tryHttp3First()) {
@@ -382,12 +384,40 @@ void libhttppp::HttpClient::resetConnection(){
    }
  } else {
    _cltsock = std::make_unique<netplus::tcp>(-1);
    _cltsock->connect(_url.getHost(), _url.getPort(), false);
    _cltsock->setNonBlock();
    _connectTcp(*_cltsock);
    _isH2 = false;
  }
}

// Plain-TCP connect bounded by _recvTimeoutSec instead of the OS default
// connect timeout (which can be minutes) -- a fully unreachable host (dead
// container, wrong IP, dropped SYNs) would otherwise hang the caller far
// longer than any configured setTimeout() would suggest.
void libhttppp::HttpClient::_connectTcp(netplus::socket &sock) {
    try {
        sock.connect(_url.getHost(), _url.getPort(), true);
        // Connected immediately (rare for TCP, but handle it)
        return;
    } catch (netplus::NetException &e) {
        if (e.getErrorType() != netplus::NetException::Note)
            throw;
    }

    if (!_sw.waitWrite(sock, _recvTimeoutSec * 1000)) {
        HTTPException he;
        he[HTTPException::Error] << "tcp connect timeout after " << _recvTimeoutSec << "s";
        throw he;
    }

    int err = 0;
    socklen_t errlen = sizeof(err);
    if (::getsockopt(sock.fd(), SOL_SOCKET, SO_ERROR, &err, &errlen) != 0 || err != 0) {
        HTTPException he;
        he[HTTPException::Error] << "tcp connect failed: " << strerror(err);
        throw he;
    }
}


void libhttppp::HttpClient::reconnect(){
  // Reset HTTP/2 and HTTP/3 connection state on reconnect
@@ -462,8 +492,7 @@ void libhttppp::HttpClient::reconnect(){
    }
  } else {
    _cltsock = std::make_unique<netplus::tcp>(-1);
    _cltsock->connect(_url.getHost(), _url.getPort(), false);
    _cltsock->setNonBlock();
    _connectTcp(*_cltsock);
    _isH2 = false;
  }
}
+9 −1
Original line number Diff line number Diff line
@@ -88,7 +88,11 @@ namespace libhttppp {

  class HttpClient{
  public:
      HttpClient( const HttpUrl &desturl, int vers = 2);
      // timeoutSec bounds the constructor's own eager connection attempt
      // (see resetConnection()) in addition to being the initial value
      // setTimeout() would otherwise set afterward -- too late to affect
      // that first connect.
      HttpClient( const HttpUrl &desturl, int vers = 2, int timeoutSec = 60);
      ~HttpClient()=default;
      void reconnect();
      void setTimeout(int timeout_sec);
@@ -146,6 +150,10 @@ namespace libhttppp {
      static netplus::TlsSessionCache& tlsSessionCache();
  private:
      void _ensureConnected();
      // Non-blocking connect + waitWrite, bounded by _recvTimeoutSec, so an
      // unreachable host (dead container, wrong IP, dropped SYNs) fails
      // within the configured timeout instead of the OS default (minutes).
      void _connectTcp(netplus::socket &sock);
      bool tryHttp3First();
      int readchunk(const char *data,int datasize,int &pos);