#define INITGUID 1 #include #include #include #include #include "hxver.h" #include "hxtypes.h" #include "hxcom.h" #include "hxcomm.h" #include "ihxpckts.h" #include "hxplugn.h" #include "hxmon.h" #include "hxfiles.h" #include "sp.h" #include "sp_func.h" #include "sp_events.h" #include "balance.h" /**************************************************************************** * HXCreateInstance ref: hxplugn.h * * This routine creates a new instance of the CBalance class. * It is called when the Helix server application is launched. */ STDAPI HXCreateInstance(IUnknown** ppInterfaceObj) { *ppInterfaceObj = (IUnknown*)(IHXPlugin*)new CBalance(); if (*ppInterfaceObj != NULL) { (*ppInterfaceObj)->AddRef(); return HXR_OK; } return HXR_OUTOFMEMORY; } /**************************************************************************** * CBalance static variables ref: exallow.h * * These variables are passed to the Helix server to provide information about * this plug-in. They are required to be static in order to remain valid * for the lifetime of the plug-in. */ const char* CBalance::zm_pDescription = MY_DESCRIPTION; const char* CBalance::zm_pCopyright = HXVER_COPYRIGHT; const char* CBalance::zm_pMoreInfoURL = HXVER_MOREINFO; /**************************************************************************** * CBalance::CBalance ref: exallow.h * * Constructor */ CBalance::CBalance(void) : m_RefCount (0), m_pClassFactory (NULL), m_pRegistry (NULL), m_pPropWatch (NULL), m_pScheduler (NULL), sp_connected (false) { } /**************************************************************************** * IHXPlugin::GetPluginInfo ref: hxplugn.h * * This routine returns descriptive information about the plug-in. It is * called when the Helix server application is launched. */ STDMETHODIMP CBalance::GetPluginInfo ( REF(BOOL) bLoadMultiple, REF(const char*) pDescription, REF(const char*) pCopyright, REF(const char*) pMoreInfoURL, REF(UINT32) ulVersionNumber ) { bLoadMultiple = false; // general plugin => load once in a new thread! pDescription = zm_pDescription; pCopyright = zm_pCopyright; pMoreInfoURL = zm_pMoreInfoURL; ulVersionNumber = MY_PLUGIN_VERSION; return HXR_OK; } /**************************************************************************** * IHXPlugin::InitPlugin ref: hxplugn.h * * This routine performs initialization steps such as determining if * required interfaces are available. It is called when the Helix core * application is launched, and whenever a new player Allowance object * is needed. */ STDMETHODIMP CBalance::InitPlugin(IUnknown* pContext) { /* * Store a reference to the IHXCommonClassFactory interface which is * used to create commonly used Helix objects such as IHXPacket, * IHXValues, and IHXBuffers. */ pContext->QueryInterface(IID_IHXCommonClassFactory, (void**)&m_pClassFactory); if (m_pClassFactory == NULL) { return HXR_NOTIMPL; } /* * Store a reference to the IHXRegistry interface which is * used to retrieve useful information about the connected player */ pContext->QueryInterface(IID_IHXRegistry, (void**)&m_pRegistry); if (m_pRegistry == NULL) { return HXR_NOTIMPL; } /* Store a reference to the scheduler */ pContext->QueryInterface(IID_IHXScheduler, (void**)&m_pScheduler); if (m_pScheduler == NULL) { return HXR_NOTIMPL; } /* * Create a PropWatch with 'this' as the callback object. */ m_pRegistry->CreatePropWatch(m_pPropWatch); if (m_pPropWatch == NULL) { return HXR_UNEXPECTED; } m_pPropWatch->Init((IHXPropWatchResponse *)this); m_pPropWatch->SetWatchByName("server.ClientCount"); /* * * Connect to the spread daemon and a group. * */ int ret = SP_connect("4803@localhost", NULL, 0, 1, &m_mbox, m_private_group); FILE* pConsole = stdout; if(ret != ACCEPT_SESSION) { fprintf(pConsole, "Could not connect to spreadd\n"); } else { fprintf(pConsole, "Connected to spreadd\n"); } if(SP_join(m_mbox, SPREAD_GROUP) != 0) { fprintf(pConsole, "Couldn't connect to group.\n"); } else { fprintf(pConsole, "Connected to group.\n"); sp_connected = true; } fflush(pConsole); // Schedule ourselves for checking the spread stuff after 1 second m_pScheduler->RelativeEnter((IHXCallback*)this, 1000); return HXR_OK; } /**************************************************************************** * CBalance::~CBalance ref: exallow.h * * Destructor */ CBalance::~CBalance(void) { /* * Disconnect from the spread group and then from the spread daemon. * Need error checking to see if we were connected in the first place. */ if(sp_connected) { FILE* pConsole = stdout; if(SP_leave(m_mbox, SPREAD_GROUP) != 0) { fprintf(pConsole, "Couldn't leave group\n"); } else { fprintf(pConsole, "Left the group OK\n"); } int ret = SP_disconnect(m_mbox); if(ret == ILLEGAL_SESSION) { fprintf(pConsole, "Could not disconnect from spreadd\n"); } else { fprintf(pConsole, "Disconnected from spreadd OK\n"); } fflush(pConsole); } // sp_connected if (m_pClassFactory) { m_pClassFactory->Release(); m_pClassFactory = NULL; } if(m_pScheduler) { m_pScheduler->Release(); m_pScheduler = NULL; } if (m_pRegistry) { m_pRegistry->Release(); m_pRegistry = NULL; } if(m_pPropWatch) { m_pPropWatch->Release(); m_pPropWatch = NULL; } } /**************************************************************************** * IHXCallback::Func() */ STDMETHODIMP CBalance::Func(void) { FILE* pConsole = stdout; int numBytes = SP_poll(m_mbox); if(numBytes < 0) { fprintf(pConsole, "Error accessing mailbox!\n"); } else if(numBytes == 0){ fprintf(pConsole, "No messages available\n"); } else { // message available while(SP_poll(m_mbox) > 0) { service service_type = 0; char sender[MAX_GROUP_NAME]; int num_groups; int max_groups = 10; char groups[10][MAX_GROUP_NAME]; int16 mess_type; int endian_mismatch; int max_mess_len = 100; char mess[100]; int message_size = SP_receive( m_mbox, // connection to receive a message on &service_type, // REG_MESSAGE or MEMBERSHIP_MESS sender, // name of sending participant max_groups, &num_groups, groups, &mess_type, &endian_mismatch, max_mess_len, mess); if(Is_regular_mess(service_type)) { fprintf(pConsole, "Received message from[%s].\n", sender); if(endian_mismatch) { fprintf(pConsole, "Endians mismatched\n."); } fprintf(pConsole, "{%s}\n", mess, 2); } } } fflush(pConsole); m_pScheduler->RelativeEnter((IHXCallback*)this, 1000); return HXR_OK; } // IHXPropWatch Interface methods /**************************************************************************** * * */ STDMETHODIMP CBalance::AddedProp( const UINT32 id, const HXPropType propType, const UINT32 ulParentID ) { return HXR_OK; } STDMETHODIMP CBalance::DeletedProp( const UINT32 id, const UINT32 ulParentID ) { return HXR_OK; } STDMETHODIMP CBalance::ModifiedProp( const UINT32 id, const HXPropType propType, const UINT32 ulParentID ) { FILE* pConsole = stdout; INT32 pPlayers = 0; m_pRegistry->GetIntById(id, pPlayers); char my_message[100]; sprintf(my_message, "%i connected clients\n", pPlayers); int msize = strlen(my_message); fprintf(pConsole, my_message); if(SP_multicast(m_mbox, RELIABLE_MESS, SPREAD_GROUP, 0, msize, my_message) <= 0) { fprintf(pConsole, "Couldn't say hello to the group.\n"); } fflush(pConsole); return HXR_OK; } // IUnknown COM Interface Methods /**************************************************************************** * IUnknown::AddRef ref: hxcom.h * * This routine increases the object reference count in a thread safe * manner. The reference count is used to manage the lifetime of an object. * This method must be explicitly called by the user whenever a new * reference to an object is used. */ STDMETHODIMP_(UINT32) CBalance::AddRef(void) { return InterlockedIncrement(&m_RefCount); } /**************************************************************************** * IUnknown::Release ref: hxcom.h * * This routine decreases the object reference count in a thread safe * manner, and deletes the object if no more references to it exist. It must * be called explicitly by the user whenever an object is no longer needed. */ STDMETHODIMP_(UINT32) CBalance::Release(void) { if (InterlockedDecrement(&m_RefCount) > 0) { return m_RefCount; } delete this; return 0; } /**************************************************************************** * IUnknown::QueryInterface ref: hxcom.h * * This routine indicates which interfaces this object supports. If a given * interface is supported, the object's reference count is incremented, and * a reference to that interface is returned. Otherwise a NULL object and * error code are returned. This method is called by other objects to * discover the functionality of this object. */ STDMETHODIMP CBalance::QueryInterface ( REFIID interfaceID, void** ppInterfaceObj ) { // By definition all COM objects support the IUnknown interface if (IsEqualIID(interfaceID, IID_IUnknown)) { AddRef(); *ppInterfaceObj = (IUnknown*)(IHXPlugin*)this; return HXR_OK; } // IHXPlugin interface is supported else if (IsEqualIID(interfaceID, IID_IHXPlugin)) { AddRef(); *ppInterfaceObj = (IHXPlugin*)this; return HXR_OK; } // No other interfaces are supported *ppInterfaceObj = NULL; return HXR_NOINTERFACE; }