/*========================================================================== * * 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;ilpguid)) { // 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