2 Commits
Author SHA1 Message Date
Jens GeyerandClaude Opus 5 b50cbfdbb2 THRIFT-6191: Keep AI_V4MAPPED out of the server sockets' resolve flags
Client: cpp

The previous commit resolved the bind address with
AI_PASSIVE|AI_V4MAPPED|AI_ADDRCONFIG and fell back to AI_PASSIVE|AI_V4MAPPED,
on the grounds that AI_V4MAPPED is ignored for AF_UNSPEC queries. That holds
for glibc but not for Android: bionic's getaddrinfo() fails any flag outside
its AI_MASK, which does not include AI_V4MAPPED, with EAI_BADFLAGS before it
looks at the family. With the ANDROID branch gone, both attempts were rejected
there and every TCP server socket's listen() threw "Could not resolve host for
server socket." -- the case ab72ebe56 had worked around.

Resolve with exactly the flags TSocket::open() uses instead,
AI_PASSIVE|AI_ADDRCONFIG and then AI_PASSIVE alone. On glibc nothing changes
-- both flag sets give the same addresses for "localhost", "::1", "127.0.0.1"
and the wildcard -- and on Android the first attempt is what the ANDROID
branch passed, so it resolves as before and only gains the fallback.

AddressResolutionHelper's default flags carried the same AI_V4MAPPED. Nothing
in the library relies on the default, but the header is installed, so it now
defaults to AI_ADDRCONFIG alone. TServerExceptionTest.cpp explained its fixed
127.0.0.1 with the servers' old flags; that comment no longer describes the
library and is reworded.

Nothing in CI builds for Android, so bionic's flag check was emulated with an
LD_PRELOAD getaddrinfo() that rejects flags outside its AI_MASK. Before this
commit TNonblockingServerTest and TServerExceptionTest fail under it; after
it they pass, and so does TServerSocketTest.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0167dH5uDP18NpE5dNpnbzfK
2026-09-14 23:49:35 +02:00
Jens GeyerandClaude Opus 5 715316da58 Keep one client's failure from ending the server
Client: cpp

TConnectedClient::run() caught TTransportException and TException and nothing
else, so any other exception left the client loop. Where it went from there
depends on the server: TSimpleServer runs the loop on the serve thread, so it
escaped serve() and the listening socket closed; TThreadedServer runs it on a
thread of its own, whose entry point has no handler either. Neither has anything
above it that catches, so the process ended.

Measured, one request whose processing throws std::bad_alloc:

  TThreadedServer    SIGABRT
  TSimpleServer      SIGABRT
  TThreadPoolServer  survives -- the thread manager's worker catches it

Three of the four servers, and the exception need not come from a handler:
reading a message whose declared sizes do not fit in memory raises std::bad_alloc
before any generated per-function try is entered, which is why the C++ generated
dispatch does not turn it into a TApplicationException.

The loop now also catches std::exception and everything else, doing what the
TException clause beside it already does -- log it and disconnect, which is what
that clause's own comment says it is for. cleanup() runs as before.

lib/cpp/test/TServerExceptionTest.cpp covers all three servers and is wired into
both CMakeLists.txt and Makefile.am; a test in only one of them is a test that
does not run under ctest. Two of the three cases fail against the unmodified
library. It binds 127.0.0.1 rather than localhost on purpose: TServerSocket
resolves with AI_V4MAPPED and TSocket with AI_ADDRCONFIG, so where localhost is
::1 and the loopback has no IPv6 address the two disagree and the test measures
that instead (THRIFT-6191).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 22:15:23 +02:00