Skip to content

Commit 48a9850

Browse files
committed
EC: forward CLibSocket::OnLost to CECSocket::OnLost so EOF actually flips the UI
CECMuleSocket multi-inherits from CECSocket (EC protocol layer) and CLibSocket (transport layer). Both declare `virtual void OnLost()` with identical signature, so they live in separate vtables in the combined object and there's no shared override. The Asio reactor's HandleRead (LibSocketAsio.cpp) calls socket->OnLost() through the CLibSocket vtable on EOF / peer-FIN — but that vtable slot is the empty CLibSocket::OnLost(){} default, because nothing was overriding the LibSocket-side virtual. CRemoteConnect::OnLost and CECServerSocket::OnLost (the ones that actually flip the GUI to disconnected and release server-side state) override the *CECSocket* side and never get called from the Asio path. End result on the wire: amuled closes the EC socket, amulegui / amuleweb's kernel receives FIN and parks the socket in CLOSE_WAIT, the Asio reactor reports EOF, dispatch lands in the empty stub, and the client process happily sits "connected" forever. Verified live on a Linux VM in this branch's previous keepalive-only commit — the TCP-layer teardown via keepalive eventually fires (~60s) but application-level state never reacts. Fix mirrors the existing OnConnect(int) pattern in CECMuleSocket: disambiguate by signature. * CLibSocket::OnLost() → OnLost(int) (param ignored, exists only to give the LibSocket-side virtual a different signature from the EC-side one). * LibSocketAsio.cpp dispatch updated to call OnLost(0). * CWebSocket::OnLost overrides on the new signature (amuleweb's HTTP-side socket inherits CLibSocket directly so this is the right hook there). * New CECMuleSocket::OnLost(int) forwards to CECSocket::OnLost() through a static_cast<CECSocket*>(this) call so virtual dispatch finds the most-derived override (CRemoteConnect on amulegui / amuleweb's EC side, CECServerSocket on amuled). Refs amule-project#757.
1 parent 1010338 commit 48a9850

5 files changed

Lines changed: 24 additions & 4 deletions

File tree

src/LibSocket.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,14 @@ class CLibSocket
132132
virtual void OnConnect(int) {}
133133
virtual void OnSend(int) {}
134134
virtual void OnReceive(int) {}
135-
virtual void OnLost() {}
135+
// Int argument is unused — exists to give the CLibSocket-layer
136+
// hook a different signature from CECSocket::OnLost(), so a class
137+
// that multi-inherits from both (CECMuleSocket) can override the
138+
// CLibSocket-side hook unambiguously and forward to the EC-layer
139+
// OnLost(). Without that disambiguation, the Asio reactor's
140+
// EOF-on-read dispatch lands on the empty CLibSocket::OnLost{}
141+
// instead of CRemoteConnect / CECServerSocket overrides.
142+
virtual void OnLost(int) {}
136143
virtual void OnProxyEvent(int) {}
137144

138145
private:

src/LibSocketAsio.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1772,7 +1772,7 @@ namespace MuleNotify
17721772
socket->OnProxyEvent(MULE_SOCKET_LOST);
17731773
} else {
17741774
AddDebugLogLineF(logAsio, CFormat("LibSocketLost %s") % socket->GetIP());
1775-
socket->OnLost();
1775+
socket->OnLost(0);
17761776
}
17771777
}
17781778

src/libs/ec/cpp/ECMuleSocket.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,19 @@ class CECMuleSocket : public CECSocket, public CLibSocket {
4545
virtual void OnConnect(int) { OnConnect(); } // This is called from LibSocketAsio
4646
virtual void OnSend(int) { OnOutput(); }
4747
virtual void OnReceive(int) { OnInput(); }
48+
// CLibSocket::OnLost(int) fires from the Asio reactor when the
49+
// peer FIN reaches our kernel (HandleRead returning bytes=0 or
50+
// an EOF error_code). Forward to the EC-layer CECSocket::OnLost()
51+
// virtual so CRemoteConnect / CECServerSocket overrides actually
52+
// run — without this the empty CLibSocket::OnLost(int){} default
53+
// would swallow the notification and the UI would stay "connected"
54+
// even after the connection died at the TCP layer.
55+
//
56+
// The cast to CECSocket* forces virtual dispatch through the EC
57+
// vtable, so an instance of CRemoteConnect / CECServerSocket
58+
// reaches its override. A qualified `CECSocket::OnLost()` call
59+
// would bypass virtual dispatch and only run the empty base.
60+
virtual void OnLost(int) { static_cast<CECSocket *>(this)->OnLost(); }
4861

4962
// Apply EC-tuned TCP keepalive (idle=30s / probe=10s / count=3 →
5063
// ~60s half-open detection). Called automatically from

src/webserver/src/WebSocket.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ CWebSocket::CWebSocket(CWebServerBase *parent)
5151

5252
}
5353

54-
void CWebSocket::OnLost()
54+
void CWebSocket::OnLost(int)
5555
{
5656
Close();
5757
Destroy();

src/webserver/src/WebSocket.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class CWebSocket : public CLibSocket {
4545

4646
virtual void OnSend(int);
4747
virtual void OnReceive(int);
48-
virtual void OnLost();
48+
virtual void OnLost(int);
4949

5050
void OnRequestReceived(char* pHeader, char* pData, uint32 dwDataLen);
5151

0 commit comments

Comments
 (0)