summaryrefslogblamecommitdiffstats
path: root/src/Bindings/LuaServerHandle.cpp
blob: 7b82003bb16d9165dd9ac272d27cf9b0a887f10f (plain) (tree)




















































































































































































































                                                                                                                                                                   

// LuaServerHandle.cpp

// Implements the cLuaServerHandle class wrapping the cServerHandle functionality for Lua API

#include "Globals.h"
#include "LuaServerHandle.h"
#include "LuaTCPLink.h"
#include "tolua++/include/tolua++.h"





cLuaServerHandle::cLuaServerHandle(UInt16 a_Port, cPluginLua & a_Plugin, int a_CallbacksTableStackPos):
	m_Plugin(a_Plugin),
	m_Callbacks(a_Plugin.GetLuaState(), a_CallbacksTableStackPos),
	m_Port(a_Port)
{
	LOGD("Creating LuaServerHandle at %p.", this);
}






cLuaServerHandle::~cLuaServerHandle()
{
	// If the server handle is still open, close it explicitly:
	LOGD("Deleting LuaServerHandle at %p.", this);
	Close();
}





void cLuaServerHandle::SetServerHandle(cServerHandlePtr a_ServerHandle, cLuaServerHandlePtr a_Self)
{
	ASSERT(m_ServerHandle == nullptr);  // The handle can be set only once

	m_ServerHandle = a_ServerHandle;
	m_Self = a_Self;
}





void cLuaServerHandle::Close(void)
{
	LOGD("Closing LuaServerHandle at %p.", this);

	// Safely grab a copy of the server handle:
	cServerHandlePtr ServerHandle = m_ServerHandle;
	if (ServerHandle == nullptr)
	{
		return;
	}

	// Close the underlying server handle:
	ServerHandle->Close();

	// Close all connections at this server:
	cLuaTCPLinkPtrs Connections;
	{
		cCSLock Lock(m_CSConnections);
		std::swap(Connections, m_Connections);
	}
	for (auto & conn: Connections)
	{
		conn->Close();
	}
	Connections.clear();

	// Allow the internal server handle to be deallocated:
	m_ServerHandle.reset();
}





bool cLuaServerHandle::IsListening(void)
{
	// Safely grab a copy of the server handle:
	cServerHandlePtr ServerHandle = m_ServerHandle;
	if (ServerHandle == nullptr)
	{
		return false;
	}

	// Query the underlying server handle:
	return ServerHandle->IsListening();
}





void cLuaServerHandle::RemoveLink(cLuaTCPLink * a_Link)
{
	cCSLock Lock(m_CSConnections);
	for (auto itr = m_Connections.begin(), end = m_Connections.end(); itr != end; ++itr)
	{
		if (itr->get() == a_Link)
		{
			m_Connections.erase(itr);
			break;
		}
	}  // for itr - m_Connections[]
}





void cLuaServerHandle::Release(void)
{
	// Close the server, if it isn't closed yet:
	Close();

	// Allow self to deallocate:
	m_Self.reset();
}





cTCPLink::cCallbacksPtr cLuaServerHandle::OnIncomingConnection(const AString & a_RemoteIPAddress, UInt16 a_RemotePort)
{
	// If not valid anymore, drop the connection:
	if (!m_Callbacks.IsValid())
	{
		return nullptr;
	}

	// Ask the plugin for link callbacks:
	cPluginLua::cOperation Op(m_Plugin);
	cLuaState::cRef LinkCallbacks;
	if (
		!Op().Call(cLuaState::cTableRef(m_Callbacks, "OnIncomingConnection"), a_RemoteIPAddress, a_RemotePort, m_Port, cLuaState::Return, LinkCallbacks) ||
		!LinkCallbacks.IsValid()
	)
	{
		LOGINFO("cNetwork server (port %d) OnIncomingConnection callback failed in plugin %s. Dropping connection.",
			m_Port, m_Plugin.GetName().c_str()
		);
		return nullptr;
	}

	// Create the link wrapper to use with the callbacks:
	auto res = std::make_shared<cLuaTCPLink>(m_Plugin, std::move(LinkCallbacks), m_Self);

	// Add the link to the list of our connections:
	cCSLock Lock(m_CSConnections);
	m_Connections.push_back(res);

	return res;
}





void cLuaServerHandle::OnAccepted(cTCPLink & a_Link)
{
	// Check if we're still valid:
	if (!m_Callbacks.IsValid())
	{
		return;
	}

	// Notify the plugin:
	cPluginLua::cOperation Op(m_Plugin);
	if (!Op().Call(cLuaState::cTableRef(m_Callbacks, "OnAccepted"), static_cast<cLuaTCPLink *>(a_Link.GetCallbacks().get())))
	{
		LOGINFO("cNetwork server (port %d) OnAccepted callback failed in plugin %s, connection to %s:%d.",
			m_Port, m_Plugin.GetName().c_str(), a_Link.GetRemoteIP().c_str(), a_Link.GetRemotePort()
		);
		return;
	}
}





void cLuaServerHandle::OnError(int a_ErrorCode, const AString & a_ErrorMsg)
{
	// Check if we're still valid:
	if (!m_Callbacks.IsValid())
	{
		return;
	}

	// Notify the plugin:
	cPluginLua::cOperation Op(m_Plugin);
	if (!Op().Call(cLuaState::cTableRef(m_Callbacks, "OnError"), a_ErrorCode, a_ErrorMsg))
	{
		LOGINFO("cNetwork server (port %d) OnError callback failed in plugin %s. The error is %d (%s).",
			m_Port, m_Plugin.GetName().c_str(), a_ErrorCode, a_ErrorMsg.c_str()
		);
		return;
	}
}