Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

498 lines
19 KiB

/*==========================================================================
*
* Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
*
* File: Server.cpp
* Content: DNET server interface routines
*@@BEGIN_MSINTERNAL
* History:
* Date By Reason
* ==== == ======
* 07/21/99 mjn Created
* 12/23/99 mjn Hand all NameTable update sends from Host to worker thread
* 12/28/99 mjn Moved Async Op stuff to Async.h
* 01/06/00 mjn Moved NameTable stuff to NameTable.h
* 01/14/00 mjn Added pvUserContext to Host API call
* 01/16/00 mjn Moved User callback stuff to User.h
* 01/22/00 mjn Implemented DestroyClient in API
* 01/28/00 mjn Implemented ReturnBuffer in API
* 02/01/00 mjn Implemented GetCaps and SetCaps in API
* 02/01/00 mjn Implement Player/Group context values
* 02/15/00 mjn Use INFO flags in SetServerInfo and return context in GetClientInfo
* 02/17/00 mjn Implemented GetPlayerContext and GetGroupContext
* 03/17/00 rmt Added new caps functions
* 04/04/00 mjn Added TerminateSession to API
* 04/05/00 mjn Modified DestroyClient
* 04/06/00 mjn Added GetClientAddress to API
* mjn Added GetHostAddress to API
* 04/18/00 rmt Added additional paramtere validation
* 04/19/00 mjn SendTo API call accepts a range of DPN_BUFFER_DESCs and a count
* 04/24/00 mjn Updated Group and Info operations to use CAsyncOp's
* 05/31/00 mjn Added operation specific SYNC flags
* 06/23/00 mjn Removed dwPriority from SendTo() API call
* 07/09/00 mjn Cleaned up DN_SetServerInfo()
* 07/09/00 rmt Bug #38323 - RegisterLobby needs a DPNHANDLE parameter.
* 08/05/00 RichGr IA64: Use %p format specifier in DPFs for 32/64-bit pointers and handles.
* 10/11/00 mjn Take locks for CNameTableEntry::PackInfo()
* mjn Check deleted list in DN_GetClientInfo()
* 01/22/01 mjn Check closing instead of disconnecting in DN_GetClientInfo()
* 07/24/01 mjn Added DPNBUILD_NOPARAMVAL compile flag
*@@END_MSINTERNAL
*
***************************************************************************/
#include "dncorei.h"
#ifndef DPNBUILD_NOSERVER
//**********************************************************************
// Constant definitions
//**********************************************************************
//**********************************************************************
// Macro definitions
//**********************************************************************
//**********************************************************************
// Structure definitions
//**********************************************************************
//**********************************************************************
// Variable definitions
//**********************************************************************
typedef STDMETHODIMP ServerQueryInterface( IDirectPlay8Server *pInterface, DP8REFIID riid, LPVOID *ppvObj );
typedef STDMETHODIMP_(ULONG) ServerAddRef( IDirectPlay8Server *pInterface );
typedef STDMETHODIMP_(ULONG) ServerRelease( IDirectPlay8Server *pInterface );
typedef STDMETHODIMP ServerInitialize( IDirectPlay8Server *pInterface, LPVOID const lpvUserContext, const PFNDPNMESSAGEHANDLER lpfn, const DWORD dwFlags );
typedef STDMETHODIMP ServerEnumServiceProviders( IDirectPlay8Server *pInterface,const GUID *const pguidServiceProvider,const GUID *const pguidApplication,DPN_SERVICE_PROVIDER_INFO *const pSPInfoBuffer,DWORD *const pcbEnumData,DWORD *const pcReturned,const DWORD dwFlags);
typedef STDMETHODIMP ServerCancelAsyncOperation( IDirectPlay8Server *pInterface, const DPNHANDLE hAsyncHandle, const DWORD dwFlags );
typedef STDMETHODIMP ServerGetSendQueueInfo( IDirectPlay8Server *pInterface, const DPNID dpnid,DWORD *const lpdwNumMsgs, DWORD *const lpdwNumBytes, const DWORD dwFlags );
typedef STDMETHODIMP ServerGetApplicationDesc( IDirectPlay8Server *pInterface,DPN_APPLICATION_DESC *const pAppDescBuffer,DWORD *const lpcbDataSize,const DWORD dwFlags );
typedef STDMETHODIMP ServerSetApplicationDesc( IDirectPlay8Server *pInterface, const DPN_APPLICATION_DESC *const lpad, const DWORD dwFlags );
typedef STDMETHODIMP ServerGetHostAddress( IDirectPlay8Server *pInterface, IDirectPlay8Address **const prgpAddress, DWORD *const pcAddress,const DWORD dwFlags);
typedef STDMETHODIMP ServerHost( IDirectPlay8Server *pInterface,const DPN_APPLICATION_DESC *const pdnAppDesc,IDirectPlay8Address **const prgpDeviceInfo,const DWORD cDeviceInfo,const DPN_SECURITY_DESC *const pdnSecurity,const DPN_SECURITY_CREDENTIALS *const pdnCredentials,void *const pvPlayerContext,const DWORD dwFlags);
typedef STDMETHODIMP ServerSendTo( IDirectPlay8Server *pInterface, const DPNID dnid, const DPN_BUFFER_DESC *const prgBufferDesc,const DWORD cBufferDesc,const DWORD dwTimeOut, void *const pvAsyncContext, DPNHANDLE *const phAsyncHandle, const DWORD dwFlags);
typedef STDMETHODIMP ServerCreateGroup( IDirectPlay8Server *pInterface, const DPN_GROUP_INFO *const pdpnGroupInfo,void *const pvGroupContext,void *const pvAsyncContext,DPNHANDLE *const phAsyncHandle,const DWORD dwFlags);
typedef STDMETHODIMP ServerDestroyGroup( IDirectPlay8Server *pInterface, const DPNID idGroup,PVOID const pvUserContext,DPNHANDLE *const lpAsyncHandle,const DWORD dwFlags);
typedef STDMETHODIMP ServerAddClientToGroup( IDirectPlay8Server *pInterface, const DPNID idGroup, const DPNID idClient,PVOID const pvUserContext,DPNHANDLE *const lpAsyncHandle,const DWORD dwFlags);
typedef STDMETHODIMP ServerRemoveClientFromGroup( IDirectPlay8Server *pInterface, const DPNID idGroup, const DPNID idClient,PVOID const pvUserContext,DPNHANDLE *const lpAsyncHandle,const DWORD dwFlags);
typedef STDMETHODIMP ServerSetGroupInfo(IDirectPlay8Server *pInterface, const DPNID dpnid,DPN_GROUP_INFO *const pdpnGroupInfo,PVOID const pvAsyncContext,DPNHANDLE *const phAsyncHandle, const DWORD dwFlags);
typedef STDMETHODIMP ServerGetGroupInfo(IDirectPlay8Server *pInterface, const DPNID dpnid,DPN_GROUP_INFO *const pdpnGroupInfo,DWORD *const pdwSize,const DWORD dwFlags);
typedef STDMETHODIMP ServerEnumClientsAndGroups( IDirectPlay8Server *pInterface, DPNID *const lprgdnid, DWORD *const lpcdnid, const DWORD dwFlags );
typedef STDMETHODIMP ServerEnumGroupMembers( IDirectPlay8Server *pInterface, const DPNID dnid, DPNID *const lprgdnid, DWORD *const lpcdnid, const DWORD dwFlags );
typedef STDMETHODIMP ServerClose( IDirectPlay8Server *pInterface,const DWORD dwFlags);
typedef STDMETHODIMP ServerDestroyClient( IDirectPlay8Server *pInterface,const DPNID dnid,const void *const pvDestroyData,const DWORD dwDestroyDataSize,const DWORD dwFlags);
typedef STDMETHODIMP ServerReturnBuffer( IDirectPlay8Server *pInterface, const DPNHANDLE hBufferHandle,const DWORD dwFlags);
typedef STDMETHODIMP ServerGetCaps(IDirectPlay8Server *pInterface,DPN_CAPS *const pdnCaps,const DWORD dwFlags);
typedef STDMETHODIMP ServerSetCaps(IDirectPlay8Server *pInterface,const DPN_CAPS *const pdnCaps,const DWORD dwFlags);
typedef STDMETHODIMP ServerGetPlayerContext(IDirectPlay8Server *pInterface,const DPNID dpnid,PVOID *const ppvPlayerContext,const DWORD dwFlags);
typedef STDMETHODIMP ServerGetGroupContext(IDirectPlay8Server *pInterface,const DPNID dpnid,PVOID *const ppvGroupContext,const DWORD dwFlags);
typedef STDMETHODIMP ServerSetSPCaps(IDirectPlay8Server *pInterface,const GUID * const pguidSP, const DPN_SP_CAPS *const pdpspCaps, const DWORD dwFlags );
typedef STDMETHODIMP ServerGetSPCaps(IDirectPlay8Server *pInterface,const GUID * const pguidSP, DPN_SP_CAPS *const pdpspCaps,const DWORD dwFlags);
typedef STDMETHODIMP ServerGetConnectionInfo(IDirectPlay8Server *pInterface,const DPNID dpnid, DPN_CONNECTION_INFO *const pdpConnectionInfo,const DWORD dwFlags);
typedef STDMETHODIMP ServerRegisterLobby(IDirectPlay8Server *pInterface,const DPNHANDLE dpnHandle,IDirectPlay8LobbiedApplication *const pIDP8LobbiedApplication,const DWORD dwFlags);
//
// VTable for server interface
//
IDirectPlay8ServerVtbl DN_ServerVtbl =
{
(ServerQueryInterface*) DN_QueryInterface,
(ServerAddRef*) DN_AddRef,
(ServerRelease*) DN_Release,
(ServerInitialize*) DN_Initialize,
(ServerEnumServiceProviders*) DN_EnumServiceProviders,
(ServerCancelAsyncOperation*) DN_CancelAsyncOperation,
(ServerGetSendQueueInfo*) DN_GetSendQueueInfo,
(ServerGetApplicationDesc*) DN_GetApplicationDesc,
DN_SetServerInfo,
DN_GetClientInfo,
DN_GetClientAddress,
(ServerGetHostAddress*) DN_GetHostAddress,
(ServerSetApplicationDesc*) DN_SetApplicationDesc,
(ServerHost*) DN_Host,
(ServerSendTo*) DN_SendTo,
(ServerCreateGroup*) DN_CreateGroup,
(ServerDestroyGroup*) DN_DestroyGroup,
(ServerAddClientToGroup*) DN_AddClientToGroup,
(ServerRemoveClientFromGroup*) DN_RemoveClientFromGroup,
(ServerSetGroupInfo*) DN_SetGroupInfo,
(ServerGetGroupInfo*) DN_GetGroupInfo,
(ServerEnumClientsAndGroups*) DN_EnumClientsAndGroups,
(ServerEnumGroupMembers*) DN_EnumGroupMembers,
(ServerClose*) DN_Close,
(ServerDestroyClient*) DN_DestroyPlayer,
(ServerReturnBuffer*) DN_ReturnBuffer,
(ServerGetPlayerContext*) DN_GetPlayerContext,
(ServerGetGroupContext*) DN_GetGroupContext,
(ServerGetCaps*) DN_GetCaps,
(ServerSetCaps*) DN_SetCaps,
(ServerSetSPCaps*) DN_SetSPCaps,
(ServerGetSPCaps*) DN_GetSPCaps,
(ServerGetConnectionInfo*) DN_GetConnectionInfo,
(ServerRegisterLobby*) DN_RegisterLobby
};
//**********************************************************************
// Function prototypes
//**********************************************************************
//**********************************************************************
// Function definitions
//**********************************************************************
// DN_SetServerInfo
//
// Set the info for the server and propagate to client players
#undef DPF_MODNAME
#define DPF_MODNAME "DN_SetServerInfo"
STDMETHODIMP DN_SetServerInfo(IDirectPlay8Server *pInterface,
const DPN_PLAYER_INFO *const pdpnPlayerInfo,
PVOID const pvAsyncContext,
DPNHANDLE *const phAsyncHandle,
const DWORD dwFlags)
{
DIRECTNETOBJECT *pdnObject;
HRESULT hResultCode;
DPNHANDLE hAsyncOp;
PWSTR pwszName;
DWORD dwNameSize;
PVOID pvData;
DWORD dwDataSize;
CNameTableEntry *pLocalPlayer;
BOOL fConnected;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], pdpnPlayerInfo [0x%p], pvAsyncContext [0x%p], phAsyncHandle [0x%p], dwFlags [0x%lx]",
pInterface,pdpnPlayerInfo,pvAsyncContext,phAsyncHandle,dwFlags);
pdnObject = (DIRECTNETOBJECT*) GET_OBJECT_FROM_INTERFACE(pInterface);
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateSetServerInfo( pInterface , pdpnPlayerInfo, pvAsyncContext, phAsyncHandle, dwFlags ) ) )
{
DPFX(DPFPREP, 0, "Error validating setserverinfo params hr=[0x%lx]", hResultCode );
DPF_RETURN( hResultCode );
}
}
#endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
{
DPFERR( "Object is not initialized" );
DPF_RETURN(DPNERR_UNINITIALIZED);
}
pLocalPlayer = NULL;
if ((pdpnPlayerInfo->dwInfoFlags & DPNINFO_NAME) && (pdpnPlayerInfo->pwszName))
{
pwszName = pdpnPlayerInfo->pwszName;
dwNameSize = (wcslen(pwszName) + 1) * sizeof(WCHAR);
}
else
{
pwszName = NULL;
dwNameSize = 0;
}
if ((pdpnPlayerInfo->dwInfoFlags & DPNINFO_DATA) && (pdpnPlayerInfo->pvData) && (pdpnPlayerInfo->dwDataSize))
{
pvData = pdpnPlayerInfo->pvData;
dwDataSize = pdpnPlayerInfo->dwDataSize;
}
else
{
pvData = NULL;
dwDataSize = 0;
}
//
// If we are connected, we will update our entry.
// Otherwise, we will just update the DefaultPlayer.
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
if (pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED)
{
fConnected = TRUE;
}
else
{
fConnected = FALSE;
}
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if (fConnected)
{
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK)
{
DPFERR( "Could not get local player reference" );
DisplayDNError(0,hResultCode);
goto Failure;
}
DPFX(DPFPREP, 3,"Host is updating server info");
hResultCode = DNHostUpdateInfo( pdnObject,
pLocalPlayer->GetDPNID(),
pwszName,
dwNameSize,
pvData,
dwDataSize,
pdpnPlayerInfo->dwInfoFlags,
pvAsyncContext,
pLocalPlayer->GetDPNID(),
0,
&hAsyncOp,
dwFlags );
if ((hResultCode != DPN_OK) && (hResultCode != DPNERR_PENDING))
{
DPFERR("Could not request host to update group");
}
else
{
if (!(dwFlags & DPNSETSERVERINFO_SYNC))
{
DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp);
*phAsyncHandle = hAsyncOp;
//
// Release Async HANDLE since this operation has already completed (!)
//
CAsyncOp* pAsyncOp;
if (SUCCEEDED(pdnObject->HandleTable.Destroy( hAsyncOp, (PVOID*)&pAsyncOp )))
{
// Release the HandleTable reference
pAsyncOp->Release();
}
pAsyncOp = NULL;
hAsyncOp = 0;
}
}
pLocalPlayer->Release();
pLocalPlayer = NULL;
}
else
{
DNASSERT(pdnObject->NameTable.GetDefaultPlayer() != NULL);
// This function takes the lock internally
pdnObject->NameTable.GetDefaultPlayer()->UpdateEntryInfo(pwszName,dwNameSize,pvData,dwDataSize,pdpnPlayerInfo->dwInfoFlags, FALSE);
hResultCode = DPN_OK;
}
Exit:
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pLocalPlayer)
{
pLocalPlayer->Release();
pLocalPlayer = NULL;
}
goto Exit;
}
// DN_GetClientInfo
//
// Retrieve client info from the local nametable.
#undef DPF_MODNAME
#define DPF_MODNAME "DN_GetClientInfo"
STDMETHODIMP DN_GetClientInfo(IDirectPlay8Server *pInterface,
const DPNID dpnid,
DPN_PLAYER_INFO *const pdpnPlayerInfo,
DWORD *const pdwSize,
const DWORD dwFlags)
{
DIRECTNETOBJECT *pdnObject;
CNameTableEntry *pNTEntry;
CPackedBuffer packedBuffer;
HRESULT hResultCode;
DPFX(DPFPREP, 2,"Parameters: dpnid [0x%lx], pdpnPlayerInfo [0x%p], dwFlags [0x%lx]",
dpnid,pdpnPlayerInfo,dwFlags);
pdnObject = (DIRECTNETOBJECT*) GET_OBJECT_FROM_INTERFACE(pInterface);
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateGetClientInfo( pInterface , dpnid, pdpnPlayerInfo, pdwSize, dwFlags ) ) )
{
DPFX(DPFPREP, 0, "Error validating getclientinfo params hr=[0x%lx]", hResultCode );
DPF_RETURN( hResultCode );
}
}
#endif // DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
{
DPFERR( "Object is not initialized" );
DPF_RETURN(DPNERR_UNINITIALIZED);
}
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
{
DPFERR("Object is connecting / starting to host" );
DPF_RETURN(DPNERR_CONNECTING);
}
if ( !(pdnObject->dwFlags & (DN_OBJECT_FLAG_CONNECTED | DN_OBJECT_FLAG_CLOSING | DN_OBJECT_FLAG_DISCONNECTING) ) )
{
DPFERR("You must be connected / disconnecting to use this function" );
DPF_RETURN(DPNERR_NOCONNECTION);
}
pNTEntry = NULL;
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry)) != DPN_OK)
{
DPFERR("Could not retrieve name table entry");
DisplayDNError(0,hResultCode);
//
// Try deleted list
//
if ((hResultCode = pdnObject->NameTable.FindDeletedEntry(dpnid,&pNTEntry)) != DPN_OK)
{
DPFERR("Could not find player in deleted list either");
DisplayDNError(0,hResultCode);
hResultCode = DPNERR_INVALIDPLAYER;
goto Failure;
}
}
packedBuffer.Initialize(pdpnPlayerInfo,*pdwSize);
pNTEntry->Lock();
if (pNTEntry->IsGroup() || pNTEntry->IsHost())
{
DPFERR( "Specified ID is invalid" );
pNTEntry->Unlock();
hResultCode = DPNERR_INVALIDPLAYER;
goto Failure;
}
hResultCode = pNTEntry->PackInfo(&packedBuffer);
pNTEntry->Unlock();
pNTEntry->Release();
pNTEntry = NULL;
if ((hResultCode == DPN_OK) || (hResultCode == DPNERR_BUFFERTOOSMALL))
{
*pdwSize = packedBuffer.GetSizeRequired();
}
Exit:
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pNTEntry)
{
pNTEntry->Release();
pNTEntry = NULL;
}
goto Exit;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DN_GetClientAddress"
STDMETHODIMP DN_GetClientAddress(IDirectPlay8Server *pInterface,
const DPNID dpnid,
IDirectPlay8Address **const ppAddress,
const DWORD dwFlags)
{
DIRECTNETOBJECT *pdnObject;
CNameTableEntry *pNTEntry;
IDirectPlay8Address *pAddress;
HRESULT hResultCode;
DPFX(DPFPREP, 2,"Parameters : pInterface [0x%p], dpnid [0x%lx], ppAddress [0x%p], dwFlags [0x%lx]",
pInterface,dpnid,ppAddress,dwFlags);
pdnObject = (DIRECTNETOBJECT*) GET_OBJECT_FROM_INTERFACE(pInterface);
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateGetClientAddress( pInterface , dpnid, ppAddress, dwFlags ) ) )
{
DPFX(DPFPREP, 0, "Error validating getclientaddress params hr=[0x%lx]", hResultCode );
DPF_RETURN( hResultCode );
}
}
#endif // DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
{
DPFERR( "Object is not initialized" );
DPF_RETURN(DPNERR_UNINITIALIZED);
}
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
{
DPFERR("Object is connecting / starting to host" );
DPF_RETURN(DPNERR_CONNECTING);
}
if ( !(pdnObject->dwFlags & (DN_OBJECT_FLAG_CONNECTED | DN_OBJECT_FLAG_CLOSING | DN_OBJECT_FLAG_DISCONNECTING) ) )
{
DPFERR("You must be connected / disconnecting to use this function" );
DPF_RETURN(DPNERR_NOCONNECTION);
}
pNTEntry = NULL;
pAddress = NULL;
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry)) != DPN_OK)
{
DPFERR("Could not find NameTableEntry");
DisplayDNError(0,hResultCode);
hResultCode = DPNERR_INVALIDPLAYER;
goto Failure;
}
if ((pNTEntry->GetAddress() == NULL) || (pNTEntry->IsGroup()) || !pNTEntry->IsAvailable())
{
DPFERR( "Specified player is not valid" );
hResultCode = DPNERR_INVALIDPLAYER;
goto Failure;
}
hResultCode = IDirectPlay8Address_Duplicate(pNTEntry->GetAddress(),ppAddress);
pNTEntry->Release();
pNTEntry = NULL;
Exit:
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pNTEntry)
{
pNTEntry->Release();
pNTEntry = NULL;
}
goto Exit;
}
#endif // DPNBUILD_NOSERVER