Skip to content

fix(indy): corrige keep-alive no Linux com Indy antigo e moderno - #624

Merged
regyssilveira merged 1 commit into
HashLoad:masterfrom
regyssilveira:codex/fix-623-indy-linux-keepalive
Oct 29, 2026
Merged

regyssilveira merged 1 commit into
HashLoad:masterfrom
regyssilveira:codex/fix-623-indy-linux-keepalive

Conversation

@regyssilveira

Copy link
Copy Markdown
Contributor

Problema

Corrige o Socket Error #22 da issue #623 na configuração de TCP keep-alive dos providers Indy.

As implementações de SetKeepAliveValues não têm o mesmo comportamento entre versões do Indy:

Implementação no Linux 60000, 1000 60, 1
Indy antigo distribuído com Delphi 11 Envia os valores diretamente ao kernel; erro 22 Configura 60 s / 1 s
Indy distribuído com Delphi 12/13 Converte milissegundos; configura 60 s / 1 s Converte para zero; erro 22

O Linux recebe TCP_KEEPIDLE e TCP_KEEPINTVL em segundos. Por isso, trocar os números indiscriminadamente para todo Linux corrigiria o Indy antigo e quebraria o moderno. Também não é seguro inferir o contrato apenas pela versão do Delphi, pois o usuário pode atualizar o Indy separadamente.

Solução

  • Centraliza a configuração em THorseIndySocket.ConfigureKeepAlive, usada por Console, Daemon e VCL.
  • No Linux, configura as opções nativas pelo binding: SO_KEEPALIVE=1, TCP_KEEPIDLE=60 e TCP_KEEPINTVL=1. Isso independe da conversão implementada em SetKeepAliveValues.
  • No Windows, preserva a chamada original SetKeepAliveValues(True, 60000, 1000). O mesmo caminho anterior é preservado nas demais plataformas fora de Linux.
  • A nova unit não introduz dependências Indy no caminho FPC.

Regressão reproduzível

Adiciona tests/indy-keepalive, com dois executáveis, runner PowerShell, linker Linux e Dockerfile:

  • Sockets reais IPv4/IPv6: controle da chamada anterior, leitura por getsockopt dos valores efetivos, configuração repetida e verificação de SO_KEEPALIVE.
  • Windows: um stack de registro confirma que os argumentos continuam sendo exatamente True, 60000, 1000, delegando a operação ao stack Windows real.
  • HTTP: três conexões independentes ao provider real, verificando HTTP 200 e o corpo. No Linux, repete com um stack que modela o contrato antigo em segundos, mantendo reais as operações nativas do socket.
  • Indy antigo real: recompila os fontes originais do Indy do Delphi 11 com Delphi 12/Linux, usando VER350 para compatibilidade dos defines desse Indy. O controle reproduz erro 22 e a configuração corrigida passa. Esse cenário é de sockets; não é uma compilação produzida pelo Delphi 11/Linux nem um teste HTTP completo com todas as dependências antigas.
  • Controle anterior à correção: com os providers originais e o contrato antigo, o teste HTTP falha por conexão resetada. Com a correção, ambas as variantes HTTP passam.

Resultados locais

Ambiente Cobertura aprovada
Delphi 10/11/12/13, Windows Console e VCL: argumentos originais, sockets IPv4/IPv6 e três respostas HTTP 200 por cenário
Delphi 13, Windows, Radix Console e VCL: mesmos testes
Delphi 12, Linux, Tree Console e Daemon: sockets e HTTP com stack padrão e modelo do contrato antigo
Delphi 13, Linux, Radix Console e Daemon: sockets e HTTP com stack padrão e modelo do contrato antigo
Fontes Indy do Delphi 11 recompilados com Delphi 12/Linux Controle com erro 22 e correção aprovada em IPv4/IPv6
FPC 3.2.2/Linux Nova unit compila com o caminho Indy excluído pelos guards

Os cenários positivos de HTTP acima totalizam 54 conexões. Os testes Windows ficam com detecção de vazamentos ativada, sem vazamentos inesperados nas execuções finais. git diff --check passou.

O Daemon é executado no container como filho direto do PID 1, validando seu listener sem fazer double fork. Não é reivindicada cobertura de daemonização, TLS ou HTTP IPv6. Os testes de socket cobrem IPv6.

Falha preexistente na suíte geral

A suíte geral Delphi 13 foi executada em Tree e Radix: 335 testes por configuração, 334 aprovados, 1 falha, 0 erros. A falha é Tests.Horse.Core.Middleware.TTestHorseCoreMiddleware.TestMiddlewareExceptionPropagation, que espera EOSError saindo de Execute, enquanto o fallback atual trata a exceção.

Um controle separado, compilado com os fontes do master anterior à correção, reproduziu exatamente a mesma falha (fixture com 5 testes, 4 aprovados e 1 falha). Portanto, a suíte geral não é apresentada como integralmente aprovada, e esse comportamento não foi alterado nesta PR. Os relatórios das falhas foram preservados localmente em benchmarks/results.

Reprodução

docker build -t horse-indy-tests:latest tests/indy-keepalive
./tests/indy-keepalive/run-keepalive.ps1 -Version 23.0 -Platform Linux -Provider Console
./tests/indy-keepalive/run-keepalive.ps1 -Version 37.0 -Platform Linux -Provider Daemon -Radix
./tests/indy-keepalive/run-keepalive.ps1 -Version 17.0 -Platform Windows -Provider Console
./tests/indy-keepalive/run-keepalive.ps1 -Version 37.0 -Platform Windows -Provider VCL

O README inclui o comando para os fontes antigos do Indy e o controle negativo com -HorseSource. Os testes dependem de uma instalação licenciada do Delphi e foram executados localmente; os jobs públicos de FPC do GitHub Actions não substituem essa validação.

Fixes #623

@regyssilveira
regyssilveira merged commit 7becbae into HashLoad:master Oct 29, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

"Socket Error #22" in a Linux environment when setting AContext.Binding.SetKeepAliveValues

1 participant