Fix DB warning and a client-connection-blocking accept() busy-loop
- runtime.sql: widen starttime to varchar(32). ctime() produces 25 chars; MariaDB's default strict mode rejects the 20-char column instead of silently truncating like the original MySQL 5.0 target did. - SocketServer.cpp/SocketBase.cpp: the accept-loop's select() used `maxfd` set only from `sock`, never updated for the ISC sockets (sckISC/sckISCII). Any fd beyond nfds is left however FD_SET last set it, since select() never examines it -- so those bits stayed permanently "set", and the server treated them as always-ready. For the login server specifically this was fatal: its sckISC is created but never listen()'d (the login server has no inbound ISC use), so accept() on it returned EINVAL on every single loop iteration, spinning the login server's CPU and spamming the log without ever getting to the real client-facing accept() in a timely way. Root-caused with a real client connecting for the first time (this path was never exercised end-to-end before). Fixed by including the ISC sockets in maxfd and skipping the ISC accept branch entirely for the login server. Also initialize sckISC/sckISCII to INVALID_SOCKET in the constructor -- they were previously left uninitialized for server types that never touch them. - tools/rose_login_test.cpp: protocol-level login smoke test. Links directly against Src/Common/rosecrypt.cpp (the server's own encryption code) rather than reimplementing the crypto, so there's no risk of a second, subtly-wrong implementation. Documents the wire handshake (0x703 encryption request -> 0x7FF -> 0x708 login, password[32]+username[16] payload) for future reference. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
764fcb3b3f
commit
1f626c6b93
4 files changed
+178
-3
No files matched your search
@@ -24,6 +24,8 @@
|
||||
CBaseSocket::CBaseSocket( )
|
||||
{
|
||||
sock = INVALID_SOCKET;
|
||||
sckISC = INVALID_SOCKET;
|
||||
sckISCII = INVALID_SOCKET;
|
||||
isActive = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -253,6 +253,13 @@ void CServerSocket::ServerLoop( )
|
||||
SOCKET NewSocket;
|
||||
timeval timeout;
|
||||
maxfd = sock;
|
||||
// select()'s nfds must cover every fd we FD_SET below, including the
|
||||
// ISC sockets -- otherwise select() silently ignores their bits and
|
||||
// leaves them however FD_SET last left them (i.e. permanently "ready"),
|
||||
// so accept() gets called on a socket with nothing pending (or, for the
|
||||
// login server, one that was never even listen()'d) and spins on EINVAL.
|
||||
if ( sckISC != INVALID_SOCKET && (int)sckISC > maxfd ) maxfd = sckISC;
|
||||
if ( sckISCII != INVALID_SOCKET && (int)sckISCII > maxfd ) maxfd = sckISCII;
|
||||
OnServerStep();
|
||||
do
|
||||
{
|
||||
@@ -272,7 +279,12 @@ void CServerSocket::ServerLoop( )
|
||||
FD_ZERO( &fds );
|
||||
if(!Config.usethreads)
|
||||
FillFDS( &fds );
|
||||
FD_SET( sckISC, &fds );
|
||||
// The login server never listen()s on sckISC (it has no inbound
|
||||
// ISC use), and select() reports a never-listening socket as
|
||||
// "readable" too (accept() on it fails without blocking) -- so
|
||||
// adding it here would just busy-spin this select() forever.
|
||||
if ( LOG_THISSERVER != LOG_LOGIN_SERVER )
|
||||
FD_SET( sckISC, &fds );
|
||||
activity = select( maxfd+1, &fds, NULL, NULL, &timeout );
|
||||
if ( activity == 0 )continue;
|
||||
if ( activity < 0 && errno != EINTR )
|
||||
@@ -284,7 +296,7 @@ void CServerSocket::ServerLoop( )
|
||||
#endif
|
||||
isActive = false;
|
||||
}
|
||||
if ( FD_ISSET( sckISC, &fds ) )
|
||||
if ( LOG_THISSERVER != LOG_LOGIN_SERVER && FD_ISSET( sckISC, &fds ) )
|
||||
{
|
||||
int clientinfolen = sizeof( sockaddr_in );
|
||||
#ifdef _WIN32
|
||||
|
||||
Reference in new issue
Block a user