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.
478 lines
13 KiB
478 lines
13 KiB
/*==========================================================================
|
|
*
|
|
* Copyright (C) 1996-1997 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: server.c
|
|
* Content: Methods for connecting and interrogating a lobby server
|
|
*
|
|
* History:
|
|
* Date By Reason
|
|
* ======= ======= ======
|
|
* 10/25/96 myronth Created it
|
|
* 11/20/96 myronth Implemented Logon/LogoffServer
|
|
* 2/12/97 myronth Mass DX5 changes
|
|
* 2/26/97 myronth #ifdef'd out DPASYNCDATA stuff (removed dependency)
|
|
* 3/12/97 myronth Fixed LoadSP code for DPlay3, reg & DPF bug fixes
|
|
* 3/13/97 myronth Save hInstance handle for LP DLL
|
|
* 4/3/97 myronth Changed CALLSP macro to CALL_LP
|
|
* 4/9/97 myronth Fixed structure passed to LP at DPLSPInit
|
|
* 5/8/97 myronth Purged dead code
|
|
* 6/19/97 myronth Moved setting of DPLOBBYPR_SPINTERFACE flag (#10118)
|
|
* 7/28/97 sohailm PRV_FindLPGUIDInAddressCallback was assuming pointers
|
|
* were valid after duration of call.
|
|
* 10/3/97 myronth Bumped version to DX6, added it to DPLSPInit struct (#12667)
|
|
* 10/7/97 myronth Save the LP version in the lobby struct for later use
|
|
* 11/6/97 myronth Added version existence flag and dwReserved values
|
|
* to SPDATA_INIT (#12916, #12917)
|
|
***************************************************************************/
|
|
#include "dplobpr.h"
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// Definitions
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
#define NUM_CALLBACKS( ptr ) ((ptr->dwSize-2*sizeof( DWORD ))/ sizeof( LPVOID ))
|
|
|
|
typedef struct LOOKFORSP
|
|
{
|
|
LPGUID lpguid;
|
|
LPBOOL lpbSuccess;
|
|
} LOOKFORSP, FAR * LPLOOKFORSP;
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// Functions
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_VerifySPCallbacks"
|
|
HRESULT PRV_VerifySPCallbacks(LPDPLOBBYI_DPLOBJECT this)
|
|
{
|
|
LPDWORD lpCallback;
|
|
int nCallbacks = NUM_CALLBACKS(((LPSP_CALLBACKS)this->pcbSPCallbacks));
|
|
int i;
|
|
|
|
|
|
DPF(2,"Verifying %d callbacks\n",nCallbacks);
|
|
DPF(7, "Entering PRV_VerifySPCallbacks");
|
|
DPF(9, "Parameters: 0x%08x", this);
|
|
|
|
lpCallback = (LPDWORD)this->pcbSPCallbacks + 2; // + 1 for dwSize, + 1 for dwFlags
|
|
|
|
for (i=0;i<nCallbacks ;i++ )
|
|
{
|
|
if ((lpCallback) && !VALIDEX_CODE_PTR(lpCallback))
|
|
{
|
|
DPF_ERR("SP provided bad callback pointer!");
|
|
return E_FAIL;
|
|
}
|
|
lpCallback++;
|
|
}
|
|
|
|
return DP_OK;
|
|
|
|
} // PRV_VerifySPCallbacks
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_LookForSPCallback"
|
|
BOOL FAR PASCAL PRV_LookForSPCallback(LPGUID lpguidSP, LPWSTR lpSPName,
|
|
DWORD dwMajorVersion, DWORD dwMinorVersion, LPVOID lpContext)
|
|
{
|
|
LPLOOKFORSP lplook = (LPLOOKFORSP)lpContext;
|
|
|
|
|
|
ASSERT(lpguidSP);
|
|
ASSERT(lplook);
|
|
|
|
// Check the guid and see if they match
|
|
if(IsEqualGUID(lpguidSP, lplook->lpguid))
|
|
{
|
|
// Set the flag to true and stop enumerating
|
|
*(lplook->lpbSuccess) = TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
} // PRV_LookForSPCallback
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_FindSPName"
|
|
HRESULT PRV_FindSPName(LPGUID lpguidSP, LPWSTR * lplpName,
|
|
LPDWORD lpdwReserved1, LPDWORD lpdwReserved2)
|
|
{
|
|
HKEY hkeyLobbySP=NULL, hkeySP;
|
|
WCHAR wszSPName[DPLOBBY_REGISTRY_NAMELEN];
|
|
DWORD dwIndex = 0, dwSPNameSize;
|
|
WCHAR wszGuidStr[GUID_STRING_SIZE];
|
|
DWORD dwGuidStrSize = sizeof(wszGuidStr)/sizeof(WCHAR);
|
|
DWORD dwFileStrSize = 0;
|
|
DWORD dwType = REG_SZ;
|
|
LPWSTR lpwszFile = NULL;
|
|
GUID guidSP;
|
|
LOOKFORSP look;
|
|
LONG lReturn;
|
|
BOOL bFound = FALSE;
|
|
DWORD dwError;
|
|
HRESULT hr;
|
|
DWORD dwSize;
|
|
|
|
|
|
|
|
DPF(7, "Entering PRV_FindSPName");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x", lpguidSP, lplpName);
|
|
|
|
ASSERT(lpguidSP);
|
|
ASSERT(lplpName);
|
|
|
|
|
|
// First see if it is a Lobby SP
|
|
// Open the DPLobby SP key
|
|
lReturn = OS_RegOpenKeyEx(HKEY_LOCAL_MACHINE, SZ_DPLOBBY_SP_KEY, 0,
|
|
KEY_READ, &hkeyLobbySP);
|
|
// If this fails, it just means that the DPLobby SP key doesn't exist (most
|
|
// likely), so in that case, there are no Lobby SP's to enumerate.
|
|
if(lReturn == ERROR_SUCCESS)
|
|
{
|
|
// Walk the list of Lobby SP's in the registry, enumerating them
|
|
while(!bFound)
|
|
{
|
|
|
|
// Get the next key's name
|
|
dwSPNameSize = DPLOBBY_REGISTRY_NAMELEN;
|
|
lReturn = OS_RegEnumKeyEx(hkeyLobbySP, dwIndex++, (LPWSTR)wszSPName,
|
|
&dwSPNameSize, NULL, NULL, NULL, NULL);
|
|
if(ERROR_NO_MORE_ITEMS == lReturn)
|
|
break;
|
|
else if(lReturn != ERROR_SUCCESS)
|
|
{
|
|
dwError = GetLastError();
|
|
DPF(2, "Unable to get Lobby Provider name -- skipping provider -- dwError = %u", dwError);
|
|
continue;
|
|
}
|
|
|
|
|
|
// Open the key
|
|
lReturn = OS_RegOpenKeyEx(hkeyLobbySP, (LPWSTR)wszSPName, 0,
|
|
KEY_READ, &hkeySP);
|
|
if(lReturn != ERROR_SUCCESS)
|
|
{
|
|
DPF_ERR("Unable to open Lobby Service Provider key in the registry!");
|
|
continue;
|
|
}
|
|
|
|
// Get the GUID of the SP
|
|
dwGuidStrSize = GUID_STRING_SIZE;
|
|
lReturn = OS_RegQueryValueEx(hkeySP, SZ_GUID, NULL, &dwType,
|
|
(LPBYTE)wszGuidStr, &dwGuidStrSize);
|
|
if(lReturn != ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey(hkeySP);
|
|
DPF_ERR("Unable to query GUID key value!");
|
|
continue;
|
|
}
|
|
|
|
// Convert the string to a real GUID
|
|
GUIDFromString(wszGuidStr, &guidSP);
|
|
|
|
// Check to see if the guid is the one we are looking for
|
|
if(IsEqualGUID(&guidSP, lpguidSP))
|
|
{
|
|
// Allocate memory for the filename string
|
|
lReturn = OS_RegQueryValueEx(hkeySP, SZ_PATH, NULL, &dwType,
|
|
NULL, &dwFileStrSize);
|
|
if(lReturn != ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey(hkeySP);
|
|
DPF_ERR("Unable to get the size of the SP Path string");
|
|
continue;
|
|
}
|
|
|
|
// Allocate memory for the string
|
|
lpwszFile = DPMEM_ALLOC(dwFileStrSize);
|
|
if(!lpwszFile)
|
|
{
|
|
RegCloseKey(hkeySP);
|
|
DPF_ERR("Unable to allocate memory for temporary file string");
|
|
continue;
|
|
}
|
|
|
|
// Get the filename string
|
|
lReturn = OS_RegQueryValueEx(hkeySP, SZ_PATH, NULL, &dwType,
|
|
(LPBYTE)lpwszFile, &dwFileStrSize);
|
|
if(lReturn != ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey(hkeySP);
|
|
DPF_ERR("Unable to get filename string from registry");
|
|
continue;
|
|
}
|
|
|
|
// Get the Reserved1 value
|
|
dwSize = sizeof(DWORD);
|
|
lReturn = OS_RegQueryValueEx(hkeySP, SZ_DWRESERVED1, NULL,
|
|
&dwType, (LPBYTE)lpdwReserved1, &dwSize);
|
|
if (lReturn != ERROR_SUCCESS)
|
|
{
|
|
DPF(0,"Could not read dwReserved1 lReturn = %d\n", lReturn);
|
|
// It's ok if LP doesn't have one of these...
|
|
}
|
|
|
|
// Get the Reserved2 value
|
|
dwSize = sizeof(DWORD);
|
|
lReturn = OS_RegQueryValueEx(hkeySP, SZ_DWRESERVED2, NULL,
|
|
&dwType, (LPBYTE)lpdwReserved2, &dwSize);
|
|
if (lReturn != ERROR_SUCCESS)
|
|
{
|
|
DPF(0,"Could not read dwReserved2 lReturn = %d\n", lReturn);
|
|
// It's ok if LP doesn't have one of these...
|
|
}
|
|
|
|
// We've got our information, so set the flag and bail
|
|
bFound = TRUE;
|
|
RegCloseKey(hkeySP);
|
|
break;
|
|
}
|
|
|
|
// Close the SP key
|
|
RegCloseKey(hkeySP);
|
|
}
|
|
}
|
|
|
|
// Close the Lobby SP key
|
|
if(hkeyLobbySP)
|
|
{
|
|
RegCloseKey(hkeyLobbySP);
|
|
}
|
|
|
|
// If we haven't found the SP, start checking the DPlay SP's for it
|
|
if(!bFound)
|
|
{
|
|
// Set up a struct containing the guid and a success flag
|
|
look.lpguid = lpguidSP;
|
|
look.lpbSuccess = &bFound;
|
|
|
|
// Call DirectPlayEnumerate and look for our SP
|
|
hr = DirectPlayEnumerate(PRV_LookForSPCallback, &look);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERR("Unable to enumerate DirectPlay Service Providers");
|
|
}
|
|
|
|
// If the flag is TRUE, that means we found it, so set the output
|
|
// pointer to a string containing our LobbySP for DPlay
|
|
if(bFound)
|
|
{
|
|
hr = GetString(&lpwszFile, SZ_SP_FOR_DPLAY);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERR("Unable to allocate temporary string for filename");
|
|
}
|
|
}
|
|
}
|
|
|
|
// If we haven't found the filename, return an error
|
|
if(!bFound)
|
|
return DPERR_GENERIC;
|
|
|
|
// Set the output parameter
|
|
*lplpName = lpwszFile;
|
|
|
|
return DP_OK;
|
|
|
|
} // PRV_FindSPName
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_LoadSP"
|
|
HRESULT PRV_LoadSP(LPDPLOBBYI_DPLOBJECT this, LPGUID lpguidSP,
|
|
LPVOID lpAddress, DWORD dwAddressSize)
|
|
{
|
|
SPDATA_INIT sd;
|
|
SPDATA_SHUTDOWN sdd;
|
|
LPDPLOBBYSP lpISP = NULL;
|
|
LPWSTR lpwszSP = NULL;
|
|
HANDLE hModule = NULL;
|
|
HRESULT hr;
|
|
HRESULT (WINAPI *SPInit)(LPSPDATA_INIT pSD);
|
|
DWORD dwError;
|
|
DWORD dwReserved1 = 0;
|
|
DWORD dwReserved2 = 0;
|
|
|
|
|
|
DPF(7, "Entering PRV_LoadSP");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x",
|
|
this, lpguidSP, lpAddress);
|
|
|
|
ASSERT(this);
|
|
ASSERT(lpguidSP);
|
|
|
|
|
|
// Find the requested Service Provider
|
|
hr = PRV_FindSPName(lpguidSP, &lpwszSP, &dwReserved1, &dwReserved2);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERR("Unabled to find requested LobbyProvider");
|
|
hr = DPERR_GENERIC;
|
|
goto ERROR_EXIT_LOADSP;
|
|
}
|
|
|
|
// Try to load the specified sp
|
|
hModule = OS_LoadLibrary(lpwszSP);
|
|
if (!hModule)
|
|
{
|
|
dwError = GetLastError();
|
|
DPF_ERR("Could not load service provider\n");
|
|
DPF(0, "GetLastError returned dwError = %d\n", dwError);
|
|
hr = DPERR_GENERIC;
|
|
goto ERROR_EXIT_LOADSP;
|
|
}
|
|
|
|
// Free the name string
|
|
DPMEM_FREE(lpwszSP);
|
|
lpwszSP = NULL;
|
|
|
|
// Get our DPLSPInit entry point
|
|
(FARPROC)SPInit = OS_GetProcAddress(hModule, "DPLSPInit");
|
|
if (!SPInit)
|
|
{
|
|
DPF(0,"Could not find service provider entry point");
|
|
hr = DPERR_GENERIC;
|
|
goto ERROR_EXIT_LOADSP;
|
|
}
|
|
|
|
// Get an IDPLobbySP to pass it
|
|
hr = PRV_GetInterface(this, (LPDPLOBBYI_INTERFACE *)&lpISP, &dplCallbacksSP);
|
|
if (FAILED(hr))
|
|
{
|
|
DPF(0,"Unable to get an IDPLobbySP interface. hr = 0x%08lx\n",hr);
|
|
hr = DPERR_GENERIC;
|
|
goto ERROR_EXIT_LOADSP;
|
|
}
|
|
|
|
// Alloc the callbacks
|
|
this->pcbSPCallbacks = DPMEM_ALLOC(sizeof(SP_CALLBACKS));
|
|
if (!this->pcbSPCallbacks)
|
|
{
|
|
DPF_ERR("Unable to allocate memory for SPCallback structure");
|
|
LEAVE_DPLOBBY();
|
|
hr = DPERR_OUTOFMEMORY;
|
|
goto ERROR_EXIT_LOADSP;
|
|
}
|
|
|
|
// Set up the init data struct
|
|
memset(&sd,0,sizeof(sd));
|
|
sd.lpCB = this->pcbSPCallbacks;
|
|
sd.lpCB->dwSize = sizeof(SP_CALLBACKS);
|
|
sd.lpCB->dwDPlayVersion = DPLSP_MAJORVERSION;
|
|
sd.lpISP = lpISP;
|
|
sd.lpAddress = lpAddress;
|
|
sd.dwReserved1 = dwReserved1;
|
|
sd.dwReserved2 = dwReserved2;
|
|
|
|
hr = SPInit(&sd);
|
|
if (FAILED(hr))
|
|
{
|
|
DPF_ERR("Could not start up service provider!");
|
|
goto ERROR_EXIT_LOADSP;
|
|
}
|
|
|
|
// Verify the callbacks are valid
|
|
hr = PRV_VerifySPCallbacks(this);
|
|
if (FAILED(hr))
|
|
{
|
|
DPF_ERR("Invalid callbacks from service provider!");
|
|
goto ERROR_EXIT_LOADSP;
|
|
}
|
|
|
|
// Make sure the SP version is valid
|
|
if (sd.dwSPVersion < DPLSP_DX5VERSION)
|
|
{
|
|
DPF_ERR("Incompatible version returned from lobby provider!");
|
|
// Since the init succeeded, try to call shutdown
|
|
memset(&sdd, 0, sizeof(SPDATA_SHUTDOWN));
|
|
// REVIEW!!!! -- Should we pass a valid interface pointer
|
|
// to the shutdown callback? If so, which one?
|
|
if (CALLBACK_EXISTS(Shutdown))
|
|
{
|
|
sdd.lpISP = PRV_GetDPLobbySPInterface(this);
|
|
hr = CALL_LP(this, Shutdown, &sdd);
|
|
if (FAILED(hr))
|
|
{
|
|
DPF_ERR("Could not invoke shutdown on the Lobby Provider");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
hr = DPERR_UNAVAILABLE;
|
|
goto ERROR_EXIT_LOADSP;
|
|
}
|
|
else
|
|
{
|
|
// Save the version of the lobby provider
|
|
this->dwLPVersion = sd.dwSPVersion;
|
|
}
|
|
|
|
// Set the flag which tells us we have an IDPLobbySP interface
|
|
this->dwFlags |= DPLOBBYPR_SPINTERFACE;
|
|
|
|
// Save the hInstance for the LP's DLL
|
|
this->hInstanceLP = hModule;
|
|
|
|
return DP_OK;
|
|
|
|
ERROR_EXIT_LOADSP:
|
|
|
|
// If the LP DLL was loaded, unload it
|
|
if(hModule)
|
|
{
|
|
if(!FreeLibrary(hModule))
|
|
{
|
|
dwError = GetLastError();
|
|
DPF_ERRVAL("Unable to free Lobby Provider DLL, dwError = %lu", dwError);
|
|
ASSERT(FALSE);
|
|
}
|
|
}
|
|
|
|
// Free our allocated callback table
|
|
if(this->pcbSPCallbacks)
|
|
{
|
|
DPMEM_FREE(this->pcbSPCallbacks);
|
|
this->pcbSPCallbacks = NULL;
|
|
}
|
|
|
|
return hr;
|
|
|
|
} // PRV_LoadSP
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_FindLPGUIDInAddressCallback"
|
|
BOOL FAR PASCAL PRV_FindLPGUIDInAddressCallback(REFGUID lpguidDataType, DWORD dwDataSize,
|
|
LPCVOID lpData, LPVOID lpContext)
|
|
{
|
|
// See if this chunk is our LobbyProvider GUID
|
|
if (IsEqualGUID(lpguidDataType, &DPAID_LobbyProvider))
|
|
{
|
|
// We found it, so we can stop enumerating chunks
|
|
*((LPGUID)lpContext) = *((LPGUID)lpData);
|
|
return FALSE;
|
|
}
|
|
|
|
// Try the next chunk
|
|
return TRUE;
|
|
|
|
} // PRV_FindLPGUIDInAddressCallback
|
|
|
|
|
|
|