1
0

cNetwork: Added self pointers to keep objects alive for callbacks.

Ref.: http://forum.mc-server.org/showthread.php?tid=1700&pid=17947#pid17947
This commit is contained in:
Mattes D 2015-01-23 23:01:18 +01:00
parent 9014bdfa32
commit 10cfa61fbc
5 changed files with 39 additions and 17 deletions

View File

@ -88,6 +88,8 @@ cNetworkSingleton::~cNetworkSingleton()
// Free the underlying LibEvent objects: // Free the underlying LibEvent objects:
evdns_base_free(m_DNSBase, true); evdns_base_free(m_DNSBase, true);
event_base_free(m_EventBase); event_base_free(m_EventBase);
libevent_global_shutdown();
} }

View File

@ -80,6 +80,9 @@ void cServerHandleImpl::Close(void)
{ {
conn->Shutdown(); conn->Shutdown();
} }
// Remove the ptr to self, so that the object may be freed:
m_SelfPtr.reset();
} }
@ -92,6 +95,7 @@ cServerHandleImplPtr cServerHandleImpl::Listen(
) )
{ {
cServerHandleImplPtr res = cServerHandleImplPtr{new cServerHandleImpl(a_ListenCallbacks)}; cServerHandleImplPtr res = cServerHandleImplPtr{new cServerHandleImpl(a_ListenCallbacks)};
res->m_SelfPtr = res;
if (res->Listen(a_Port)) if (res->Listen(a_Port))
{ {
cNetworkSingleton::Get().AddServer(res); cNetworkSingleton::Get().AddServer(res);
@ -99,6 +103,7 @@ cServerHandleImplPtr cServerHandleImpl::Listen(
else else
{ {
a_ListenCallbacks->OnError(res->m_ErrorCode, res->m_ErrorMsg); a_ListenCallbacks->OnError(res->m_ErrorCode, res->m_ErrorMsg);
res->m_SelfPtr.reset();
} }
return res; return res;
} }
@ -247,6 +252,7 @@ void cServerHandleImpl::Callback(evconnlistener * a_Listener, evutil_socket_t a_
// Cast to true self: // Cast to true self:
cServerHandleImpl * Self = reinterpret_cast<cServerHandleImpl *>(a_Self); cServerHandleImpl * Self = reinterpret_cast<cServerHandleImpl *>(a_Self);
ASSERT(Self != nullptr); ASSERT(Self != nullptr);
ASSERT(Self->m_SelfPtr != nullptr);
// Get the textual IP address and port number out of a_Addr: // Get the textual IP address and port number out of a_Addr:
char IPAddress[128]; char IPAddress[128];
@ -278,13 +284,13 @@ void cServerHandleImpl::Callback(evconnlistener * a_Listener, evutil_socket_t a_
} }
// Create a new cTCPLink for the incoming connection: // Create a new cTCPLink for the incoming connection:
cTCPLinkImplPtr Link = std::make_shared<cTCPLinkImpl>(a_Socket, LinkCallbacks, Self, a_Addr, static_cast<socklen_t>(a_Len)); cTCPLinkImplPtr Link = std::make_shared<cTCPLinkImpl>(a_Socket, LinkCallbacks, Self->m_SelfPtr, a_Addr, static_cast<socklen_t>(a_Len));
{ {
cCSLock Lock(Self->m_CS); cCSLock Lock(Self->m_CS);
Self->m_Connections.push_back(Link); Self->m_Connections.push_back(Link);
} // Lock(m_CS) } // Lock(m_CS)
LinkCallbacks->OnLinkCreated(Link); LinkCallbacks->OnLinkCreated(Link);
Link->Enable(); Link->Enable(Link);
// Call the OnAccepted callback: // Call the OnAccepted callback:
Self->m_ListenCallbacks->OnAccepted(*Link); Self->m_ListenCallbacks->OnAccepted(*Link);

View File

@ -78,6 +78,9 @@ protected:
/** Contains the error message for the failure to listen. Only valid for non-listening instances. */ /** Contains the error message for the failure to listen. Only valid for non-listening instances. */
AString m_ErrorMsg; AString m_ErrorMsg;
/** The SharedPtr to self, so that it can be passed to created links. */
cServerHandleImplPtr m_SelfPtr;
/** Creates a new instance with the specified callbacks. /** Creates a new instance with the specified callbacks.

View File

@ -17,8 +17,7 @@
cTCPLinkImpl::cTCPLinkImpl(cTCPLink::cCallbacksPtr a_LinkCallbacks): cTCPLinkImpl::cTCPLinkImpl(cTCPLink::cCallbacksPtr a_LinkCallbacks):
super(a_LinkCallbacks), super(a_LinkCallbacks),
m_BufferEvent(bufferevent_socket_new(cNetworkSingleton::Get().GetEventBase(), -1, BEV_OPT_CLOSE_ON_FREE)), m_BufferEvent(bufferevent_socket_new(cNetworkSingleton::Get().GetEventBase(), -1, BEV_OPT_CLOSE_ON_FREE))
m_Server(nullptr)
{ {
} }
@ -26,7 +25,7 @@ cTCPLinkImpl::cTCPLinkImpl(cTCPLink::cCallbacksPtr a_LinkCallbacks):
cTCPLinkImpl::cTCPLinkImpl(evutil_socket_t a_Socket, cTCPLink::cCallbacksPtr a_LinkCallbacks, cServerHandleImpl * a_Server, const sockaddr * a_Address, socklen_t a_AddrLen): cTCPLinkImpl::cTCPLinkImpl(evutil_socket_t a_Socket, cTCPLink::cCallbacksPtr a_LinkCallbacks, cServerHandleImplPtr a_Server, const sockaddr * a_Address, socklen_t a_AddrLen):
super(a_LinkCallbacks), super(a_LinkCallbacks),
m_BufferEvent(bufferevent_socket_new(cNetworkSingleton::Get().GetEventBase(), a_Socket, BEV_OPT_CLOSE_ON_FREE)), m_BufferEvent(bufferevent_socket_new(cNetworkSingleton::Get().GetEventBase(), a_Socket, BEV_OPT_CLOSE_ON_FREE)),
m_Server(a_Server) m_Server(a_Server)
@ -59,7 +58,7 @@ cTCPLinkImplPtr cTCPLinkImpl::Connect(const AString & a_Host, UInt16 a_Port, cTC
res->m_ConnectCallbacks = a_ConnectCallbacks; res->m_ConnectCallbacks = a_ConnectCallbacks;
cNetworkSingleton::Get().AddLink(res); cNetworkSingleton::Get().AddLink(res);
res->m_Callbacks->OnLinkCreated(res); res->m_Callbacks->OnLinkCreated(res);
res->Enable(); res->Enable(res);
// If a_Host is an IP address, schedule a connection immediately: // If a_Host is an IP address, schedule a connection immediately:
sockaddr_storage sa; sockaddr_storage sa;
@ -102,8 +101,11 @@ cTCPLinkImplPtr cTCPLinkImpl::Connect(const AString & a_Host, UInt16 a_Port, cTC
void cTCPLinkImpl::Enable(void) void cTCPLinkImpl::Enable(cTCPLinkImplPtr a_Self)
{ {
// Take hold of a shared copy of self, to keep as long as the callbacks are coming:
m_Self = a_Self;
// Set the LibEvent callbacks and enable processing: // Set the LibEvent callbacks and enable processing:
bufferevent_setcb(m_BufferEvent, ReadCallback, nullptr, EventCallback, this); bufferevent_setcb(m_BufferEvent, ReadCallback, nullptr, EventCallback, this);
bufferevent_enable(m_BufferEvent, EV_READ | EV_WRITE); bufferevent_enable(m_BufferEvent, EV_READ | EV_WRITE);
@ -148,6 +150,7 @@ void cTCPLinkImpl::Close(void)
{ {
m_Server->RemoveLink(this); m_Server->RemoveLink(this);
} }
m_Self.reset();
} }
@ -177,7 +180,7 @@ void cTCPLinkImpl::ReadCallback(bufferevent * a_BufferEvent, void * a_Self)
void cTCPLinkImpl::EventCallback(bufferevent * a_BufferEvent, short a_What, void * a_Self) void cTCPLinkImpl::EventCallback(bufferevent * a_BufferEvent, short a_What, void * a_Self)
{ {
ASSERT(a_Self != nullptr); ASSERT(a_Self != nullptr);
cTCPLinkImpl * Self = static_cast<cTCPLinkImpl *>(a_Self); cTCPLinkImplPtr Self = static_cast<cTCPLinkImpl *>(a_Self)->m_Self;
// If an error is reported, call the error callback: // If an error is reported, call the error callback:
if (a_What & BEV_EVENT_ERROR) if (a_What & BEV_EVENT_ERROR)
@ -198,13 +201,14 @@ void cTCPLinkImpl::EventCallback(bufferevent * a_BufferEvent, short a_What, void
Self->m_Callbacks->OnError(err, evutil_socket_error_to_string(err)); Self->m_Callbacks->OnError(err, evutil_socket_error_to_string(err));
if (Self->m_Server == nullptr) if (Self->m_Server == nullptr)
{ {
cNetworkSingleton::Get().RemoveLink(Self); cNetworkSingleton::Get().RemoveLink(Self.get());
} }
else else
{ {
Self->m_Server->RemoveLink(Self); Self->m_Server->RemoveLink(Self.get());
} }
} }
Self->m_Self.reset();
return; return;
} }
@ -228,12 +232,13 @@ void cTCPLinkImpl::EventCallback(bufferevent * a_BufferEvent, short a_What, void
Self->m_Callbacks->OnRemoteClosed(); Self->m_Callbacks->OnRemoteClosed();
if (Self->m_Server != nullptr) if (Self->m_Server != nullptr)
{ {
Self->m_Server->RemoveLink(Self); Self->m_Server->RemoveLink(Self.get());
} }
else else
{ {
cNetworkSingleton::Get().RemoveLink(Self); cNetworkSingleton::Get().RemoveLink(Self.get());
} }
Self->m_Self.reset();
return; return;
} }

View File

@ -21,6 +21,7 @@
// fwd: // fwd:
class cServerHandleImpl; class cServerHandleImpl;
typedef SharedPtr<cServerHandleImpl> cServerHandleImplPtr;
class cTCPLinkImpl; class cTCPLinkImpl;
typedef SharedPtr<cTCPLinkImpl> cTCPLinkImplPtr; typedef SharedPtr<cTCPLinkImpl> cTCPLinkImplPtr;
typedef std::vector<cTCPLinkImplPtr> cTCPLinkImplPtrs; typedef std::vector<cTCPLinkImplPtr> cTCPLinkImplPtrs;
@ -39,7 +40,7 @@ public:
Used for connections accepted in a server using cNetwork::Listen(). Used for connections accepted in a server using cNetwork::Listen().
a_Address and a_AddrLen describe the remote peer that has connected. a_Address and a_AddrLen describe the remote peer that has connected.
The link is created disabled, you need to call Enable() to start the regular communication. */ The link is created disabled, you need to call Enable() to start the regular communication. */
cTCPLinkImpl(evutil_socket_t a_Socket, cCallbacksPtr a_LinkCallbacks, cServerHandleImpl * a_Server, const sockaddr * a_Address, socklen_t a_AddrLen); cTCPLinkImpl(evutil_socket_t a_Socket, cCallbacksPtr a_LinkCallbacks, cServerHandleImplPtr a_Server, const sockaddr * a_Address, socklen_t a_AddrLen);
/** Destroys the LibEvent handle representing the link. */ /** Destroys the LibEvent handle representing the link. */
~cTCPLinkImpl(); ~cTCPLinkImpl();
@ -51,8 +52,9 @@ public:
/** Enables communication over the link. /** Enables communication over the link.
Links are created with communication disabled, so that creation callbacks can be called first. Links are created with communication disabled, so that creation callbacks can be called first.
This function then enables the regular communication to be reported. */ This function then enables the regular communication to be reported.
void Enable(void); The a_Self parameter is used so that the socket can keep itself alive as long as the callbacks are coming. */
void Enable(cTCPLinkImplPtr a_Self);
// cTCPLink overrides: // cTCPLink overrides:
virtual bool Send(const void * a_Data, size_t a_Length) override; virtual bool Send(const void * a_Data, size_t a_Length) override;
@ -73,8 +75,8 @@ protected:
bufferevent * m_BufferEvent; bufferevent * m_BufferEvent;
/** The server handle that has created this link. /** The server handle that has created this link.
Only valid for incoming connections, NULL for outgoing connections. */ Only valid for incoming connections, nullptr for outgoing connections. */
cServerHandleImpl * m_Server; cServerHandleImplPtr m_Server;
/** The IP address of the local endpoint. Valid only after the socket has been connected. */ /** The IP address of the local endpoint. Valid only after the socket has been connected. */
AString m_LocalIP; AString m_LocalIP;
@ -88,6 +90,10 @@ protected:
/** The port of the remote endpoint. Valid only after the socket has been connected. */ /** The port of the remote endpoint. Valid only after the socket has been connected. */
UInt16 m_RemotePort; UInt16 m_RemotePort;
/** SharedPtr to self, used to keep this object alive as long as the callbacks are coming.
Initialized in Enable(), cleared in Close() and EventCallback(RemoteClosed). */
cTCPLinkImplPtr m_Self;
/** Creates a new link to be queued to connect to a specified host:port. /** Creates a new link to be queued to connect to a specified host:port.
Used for outgoing connections created using cNetwork::Connect(). Used for outgoing connections created using cNetwork::Connect().