Started local name server framework.
diff --git a/dlls/dplayx/dplay.c b/dlls/dplayx/dplay.c
index aa790a9..a3d7c33 100644
--- a/dlls/dplayx/dplay.c
+++ b/dlls/dplayx/dplay.c
@@ -71,6 +71,8 @@
HANDLE hEnumSessionThread;
EnumSessionAsyncCallbackData enumSessionAsyncCallbackData;
+
+ LPVOID lpNameServerData; /* DPlay interface doesn't know type */
} DirectPlay2Data;
typedef struct tagDirectPlay3Data
@@ -163,6 +165,11 @@
This->dp2->enumSessionAsyncCallbackData.lpContext = NULL;
This->dp2->enumSessionAsyncCallbackData.dwTimeout = INFINITE;
+ if( !NS_InitializeSessionCache( &This->dp2->lpNameServerData ) )
+ {
+ return FALSE;
+ }
+
return TRUE;
}
@@ -175,6 +182,8 @@
TerminateThread( This->dp2->hEnumSessionThread, 0 );
CloseHandle( This->dp2->hEnumSessionThread );
}
+
+ NS_DeleteSessionCache( This->dp2->lpNameServerData );
/* Delete the contents */
HeapFree( GetProcessHeap(), 0, This->dp2 );
@@ -751,21 +760,30 @@
return DP_OK;
}
-/* This function is responsible for sending a request for all other known
- nameservers to send us what sessions they have registered locally
- */
-void DP_SendSessionRequestBroadcast()
-{
- FIXME( ": stub\n" );
-}
-
/* This function should call the registered callback function that the user
- passed into EnumSessions
+ passed into EnumSessions for each entry available.
*/
static void DP_InvokeEnumSessionCallbacksA( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
+ LPVOID lpNSInfo,
+ DWORD dwTimeout,
LPVOID lpContext )
{
- FIXME( ": stub\n" );
+ LPDPSESSIONDESC2 lpSessionDesc;
+
+ FIXME( ": not checking for conditions\n" );
+
+ NS_ResetSessionEnumeration( lpNSInfo );
+
+ /* Enumerate all sessions */
+ while( (lpSessionDesc = NS_WalkSessions( lpNSInfo ) ) != NULL )
+ {
+ TRACE( "EnumSessionsCallback2 invoked\n" );
+ if( !lpEnumSessionsCallback2( lpSessionDesc, &dwTimeout, 0, lpContext ) )
+ {
+ return;
+ }
+ }
+
}
static DWORD CALLBACK DP_EnumSessionsSpwanThreadA( LPVOID lpContext )
@@ -773,21 +791,34 @@
ICOM_THIS(IDirectPlay2Impl,lpContext);
DWORD dwTimeout = This->dp2->enumSessionAsyncCallbackData.dwTimeout;
- TRACE( "->(%p)->(0x%08lx)\n", This, dwTimeout );
+ TRACE( "(%p)->(0x%08lx)\n", This, dwTimeout );
/* FIXME: Don't think this is exactly right. It'll do for now */
for( ;; )
{
/* 2: Send the broadcast for session enumeration */
- DP_SendSessionRequestBroadcast( NULL, 0 ); /* Should pass lpsd */
+ NS_SendSessionRequestBroadcast( This->dp2->lpNameServerData );
SleepEx( dwTimeout, FALSE );
DP_InvokeEnumSessionCallbacksA( This->dp2->enumSessionAsyncCallbackData.cb,
+ This->dp2->lpNameServerData,
+ dwTimeout,
This->dp2->enumSessionAsyncCallbackData.lpContext );
+
+ /* All sessions have been enumerated. Invoke the callback function
+ once more indicating a timeout has occured. This is the way
+ that the application can indicate that it wishes to continue with the
+ enumeration */
+ if( !(This->dp2->enumSessionAsyncCallbackData.cb)( NULL, &dwTimeout, DPESC_TIMEDOUT, lpContext ) )
+ {
+ /* The application doesn't want us to continue - end this thread */
+ return 0;
+ }
+
}
- return 0;
+ return 1;
}
static HRESULT WINAPI DirectPlay2AImpl_EnumSessions
@@ -800,6 +831,8 @@
if( dwTimeout == 0 )
{
+ /* Should actually be getting the dwTimeout value through
+ IDirectPlay_GetCaps( This, ...) */
FIXME( ": should provide a dependent dwTimeout\n" );
dwTimeout = 5 * 1000; /* 5 seconds */
}
@@ -833,10 +866,14 @@
{
DWORD dwThreadId;
+ /* Enumerate everything presently in the local session cache */
+ DP_InvokeEnumSessionCallbacksA( lpEnumSessionsCallback2, This->dp2->lpNameServerData, dwTimeout, lpContext );
+
/* See if we've already created a thread to service this interface */
if( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE )
{
-
+ /* FIXME: Should be adding a reference here - another thread now knows
+ how to call this interface */
This->dp2->enumSessionAsyncCallbackData.cb = lpEnumSessionsCallback2;
This->dp2->enumSessionAsyncCallbackData.lpContext = lpContext;
This->dp2->enumSessionAsyncCallbackData.dwTimeout = dwTimeout;
@@ -851,17 +888,15 @@
&dwThreadId );
}
- DP_InvokeEnumSessionCallbacksA( lpEnumSessionsCallback2, lpContext );
}
else
{
/* Send the broadcast for session enumeration */
- /* FIXME: How to handle the replies? Queue? */
- DP_SendSessionRequestBroadcast( lpsd, dwFlags );
+ NS_SendSessionRequestBroadcast( This->dp2->lpNameServerData );
SleepEx( dwTimeout, FALSE );
- DP_InvokeEnumSessionCallbacksA( lpEnumSessionsCallback2, lpContext );
+ DP_InvokeEnumSessionCallbacksA( lpEnumSessionsCallback2, This->dp2->lpNameServerData, dwTimeout, lpContext );
}
return DP_OK;
@@ -1061,7 +1096,7 @@
/* Rightoo - this computer is the host and the local computer needs to be
the name server so that others can join this session */
- DPLAYX_NS_SetLocalComputerAsNameServer( lpsd );
+ NS_SetLocalComputerAsNameServer( lpsd );
}
@@ -1593,9 +1628,31 @@
FIXME("(%p)->(%p,0x%08lx,%p,%p): stub\n", This, lpsd, dwFlags, lpSecurity, lpCredentials );
+ if( This->dp2->bConnectionOpen )
+ {
+ TRACE( ": rejecting already open connection.\n" );
+ return DPERR_ALREADYINITIALIZED;
+ }
+
+ /* When we open we need to stop any EnumSession activity */
IDirectPlayX_EnumSessions( iface, NULL, 0, NULL, NULL, DPENUMSESSIONS_STOPASYNC );
+ if( dwFlags & DPOPEN_CREATE )
+ {
+ dwFlags &= ~DPOPEN_CREATE;
+
+ /* Rightoo - this computer is the host and the local computer needs to be
+ the name server so that others can join this session */
+ NS_SetLocalComputerAsNameServer( lpsd );
+
+ }
+ if( dwFlags )
+ {
+ ERR( ": ignored dwFlags 0x%08lx\n", dwFlags );
+ }
+
return DP_OK;
+
}
static HRESULT WINAPI DirectPlay3WImpl_SecureOpen
diff --git a/dlls/dplayx/dplayx_global.c b/dlls/dplayx/dplayx_global.c
index e959e25..bee0c82 100644
--- a/dlls/dplayx/dplayx_global.c
+++ b/dlls/dplayx/dplayx_global.c
@@ -1,6 +1,6 @@
/* dplayx.dll global data implementation.
*
- * Copyright 1999 - Peter Hunnisett
+ * Copyright 1999,2000 - Peter Hunnisett
*
* <presently under construction - contact hunnise@nortelnetworks.com>
*
@@ -36,27 +36,34 @@
/* HACK for simple global data right now */
-enum { numSupportedLobbies = 32 };
+enum { numSupportedLobbies = 32, numSupportedSessions = 32 };
typedef struct tagDirectPlayLobbyData
{
+ /* Just a DPLCONNECTION struct */
DWORD dwConnFlags;
DPSESSIONDESC2 sessionDesc;
DPNAME playerName;
GUID guidSP;
LPVOID lpAddress;
DWORD dwAddressSize;
+
+ /* Information for dplobby interfaces */
DWORD dwAppID;
HANDLE hReceiveEvent;
DWORD dwAppLaunchedFromID;
+
} DirectPlayLobbyData, *lpDirectPlayLobbyData;
static DirectPlayLobbyData lobbyData[ numSupportedLobbies ];
+/* Hack for now */
+static DPSESSIONDESC2 sessionData[ numSupportedSessions ];
+
/* Function prototypes */
BOOL DPLAYX_IsAppIdLobbied( DWORD dwAppId, lpDirectPlayLobbyData* dplData );
void DPLAYX_InitializeLobbyDataEntry( lpDirectPlayLobbyData lpData );
-
-
+BOOL DPLAYX_CopyIntoSessionDesc2A( LPDPSESSIONDESC2 lpSessionDest,
+ LPCDPSESSIONDESC2 lpSessionSrc );
@@ -87,6 +94,12 @@
DPLAYX_InitializeLobbyDataEntry( &lobbyData[ i ] );
}
+ /* Set all sessions to be "empty" */
+ for( i=0; i < numSupportedSessions; i++ )
+ {
+ sessionData[i].dwSize = 0;
+ }
+
}
/***************************************************************************
@@ -578,6 +591,89 @@
return DP_OK;
}
+LPDPSESSIONDESC2 DPLAYX_CopyAndAllocateSessionDesc2A( LPCDPSESSIONDESC2 lpSessionSrc )
+{
+ LPDPSESSIONDESC2 lpSessionDest = (LPDPSESSIONDESC2) HeapAlloc( GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ sizeof( *lpSessionSrc ) );
+ DPLAYX_CopyIntoSessionDesc2A( lpSessionDest, lpSessionSrc );
+
+ return lpSessionDest;
+}
+
+/* Copy an ANSI session desc structure to the given buffer */
+BOOL DPLAYX_CopyIntoSessionDesc2A( LPDPSESSIONDESC2 lpSessionDest,
+ LPCDPSESSIONDESC2 lpSessionSrc )
+{
+ memcpy( lpSessionDest, lpSessionSrc, sizeof( *lpSessionSrc ) );
+
+ if( lpSessionSrc->sess.lpszSessionNameA )
+ {
+ lpSessionDest->sess.lpszSessionNameA =
+ HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpSessionSrc->sess.lpszSessionNameA );
+ }
+ if( lpSessionSrc->pass.lpszPasswordA )
+ {
+ lpSessionDest->pass.lpszPasswordA =
+ HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpSessionSrc->pass.lpszPasswordA );
+ }
+
+ return TRUE;
+}
+
+/* Start the index at 0. index will be updated to equal that which should
+ be passed back into this function for the next element */
+LPDPSESSIONDESC2 DPLAYX_CopyAndAllocateLocalSession( UINT* index )
+{
+ for( ; (*index) < numSupportedSessions; (*index)++ )
+ {
+ if( sessionData[(*index)].dwSize != 0 )
+ {
+ return DPLAYX_CopyAndAllocateSessionDesc2A( &sessionData[(*index)++] );
+ }
+ }
+
+ /* No more sessions */
+ return NULL;
+}
+
+/* Start the index at 0. index will be updated to equal that which should
+ be passed back into this function for the next element */
+BOOL DPLAYX_CopyLocalSession( UINT* index, LPDPSESSIONDESC2 lpsd )
+{
+ for( ; (*index) < numSupportedSessions; (*index)++ )
+ {
+ if( sessionData[(*index)].dwSize != 0 )
+ {
+ return DPLAYX_CopyIntoSessionDesc2A( lpsd, &sessionData[(*index)++] );
+ }
+ }
+
+ /* No more sessions */
+ return FALSE;
+}
+
+void DPLAYX_SetLocalSession( LPCDPSESSIONDESC2 lpsd )
+{
+ UINT i;
+
+ FIXME( ": stub\n" );
+
+ /* FIXME: Is this an error if it exists already? */
+
+ /* Crude/wrong implementation for now. Just always add to first empty spot */
+ for( i=0; i < numSupportedSessions; i++ )
+ {
+ /* Is this one empty? */
+ if( sessionData[i].dwSize == 0 )
+ {
+ DPLAYX_CopyIntoSessionDesc2A( &sessionData[i], lpsd );
+ break;
+ }
+ }
+
+}
+
/* NOTE: This is potentially not thread safe. You are not guaranteed to end up
with the correct string printed in the case where the HRESULT is not
known. You'll just get the last hr passed in printed. This can change
diff --git a/dlls/dplayx/dplayx_global.h b/dlls/dplayx/dplayx_global.h
index 6f49e42..3310b93 100644
--- a/dlls/dplayx/dplayx_global.h
+++ b/dlls/dplayx/dplayx_global.h
@@ -16,6 +16,10 @@
BOOL DPLAYX_CreateLobbyApplication( DWORD dwAppID, HANDLE hReceiveEvent );
BOOL DPLAYX_DestroyLobbyApplication( DWORD dwAppID );
+LPDPSESSIONDESC2 DPLAYX_CopyAndAllocateLocalSession( UINT* index );
+BOOL DPLAYX_CopyLocalSession( UINT* index, LPDPSESSIONDESC2 lpsd );
+void DPLAYX_SetLocalSession( LPCDPSESSIONDESC2 lpsd );
+
/* Convert a DP or DPL HRESULT code into a string for human consumption */
LPCSTR DPLAYX_HresultToString( HRESULT hr );
diff --git a/dlls/dplayx/name_server.c b/dlls/dplayx/name_server.c
index 57188aa..d81ad57 100644
--- a/dlls/dplayx/name_server.c
+++ b/dlls/dplayx/name_server.c
@@ -8,15 +8,152 @@
/* NOTE: Methods with the NS_ prefix are name server methods */
-
+#include "winbase.h"
#include "debugtools.h"
+
+#include "dplayx_global.h"
#include "name_server.h"
+/* FIXME: Need to aquire the interface semaphore before didlling data */
+
DEFAULT_DEBUG_CHANNEL(dplay);
-
-void DPLAYX_NS_SetLocalComputerAsNameServer( LPDPSESSIONDESC2 lpsd )
+/* NS specific structures */
+typedef struct tagNSCacheData
{
- FIXME( ": (%p) stub\n", lpsd );
+ struct tagNSCacheData* next;
+
+ LPDPSESSIONDESC2 data;
+
+} NSCacheData, *lpNSCacheData;
+
+typedef struct tagNSCache
+{
+ lpNSCacheData present; /* keep track of what is to be looked at */
+ lpNSCacheData first;
+} NSCache, *lpNSCache;
+
+/* Local Prototypes */
+static void NS_InvalidateSessionCache( lpNSCache lpCache );
+
+
+/* Name Server functions
+ * ---------------------
+ */
+void NS_SetLocalComputerAsNameServer( LPCDPSESSIONDESC2 lpsd )
+{
+ DPLAYX_SetLocalSession( lpsd );
}
+/* This function is responsible for sending a request for all other known
+ nameservers to send us what sessions they have registered locally
+ */
+void NS_SendSessionRequestBroadcast( LPVOID lpNSInfo )
+{
+ UINT index = 0;
+ lpNSCache lpCache = (lpNSCache)lpNSInfo;
+ LPDPSESSIONDESC2 lpTmp = NULL;
+
+ /* Invalidate the session cache for the interface */
+ NS_InvalidateSessionCache( lpCache );
+
+ /* Add the local known sessions to the cache */
+ if( ( lpTmp = DPLAYX_CopyAndAllocateLocalSession( &index ) ) != NULL )
+ {
+ lpCache->first = (lpNSCacheData)HeapAlloc( GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ sizeof( *(lpCache->first) ) );
+ lpCache->first->data = lpTmp;
+ lpCache->first->next = NULL;
+ lpCache->present = lpCache->first;
+
+ while( ( lpTmp = DPLAYX_CopyAndAllocateLocalSession( &index ) ) != NULL )
+ {
+ lpCache->present->next = (lpNSCacheData)HeapAlloc( GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ sizeof( *(lpCache->present) ) );
+ lpCache->present = lpCache->present->next;
+ lpCache->present->data = lpTmp;
+ lpCache->present->next = NULL;
+ }
+
+ lpCache->present = lpCache->first;
+ }
+
+ /* Send out requests for matching sessions to all other known computers */
+ FIXME( ": no remote requests sent\n" );
+ /* FIXME - how to handle responses to messages anyways? */
+}
+
+/* Render all data in a session cache invalid */
+static void NS_InvalidateSessionCache( lpNSCache lpCache )
+{
+ if( lpCache == NULL )
+ {
+ ERR( ": invalidate non existant cache\n" );
+ return;
+ }
+
+ /* Remove everything from the cache */
+ while( lpCache->first )
+ {
+ lpCache->present = lpCache->first;
+ lpCache->first = lpCache->first->next;
+ HeapFree( GetProcessHeap(), 0, lpCache->present );
+ }
+
+ /* NULL out the cache pointers */
+ lpCache->present = NULL;
+ lpCache->first = NULL;
+}
+
+/* Create and initialize a session cache */
+BOOL NS_InitializeSessionCache( LPVOID* lplpNSInfo )
+{
+ lpNSCache lpCache = (lpNSCache)HeapAlloc( GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ sizeof( *lpCache ) );
+
+ *lplpNSInfo = lpCache;
+
+ if( lpCache == NULL )
+ {
+ return FALSE;
+ }
+
+ lpCache->first = lpCache->present = NULL;
+
+ return TRUE;
+}
+
+/* Delete a session cache */
+void NS_DeleteSessionCache( LPVOID lpNSInfo )
+{
+ NS_InvalidateSessionCache( (lpNSCache)lpNSInfo );
+}
+
+/* Reinitialize the present pointer for this cache */
+void NS_ResetSessionEnumeration( LPVOID lpNSInfo )
+{
+
+ ((lpNSCache)lpNSInfo)->present = ((lpNSCache)lpNSInfo)->first;
+}
+
+LPDPSESSIONDESC2 NS_WalkSessions( LPVOID lpNSInfo )
+{
+ LPDPSESSIONDESC2 lpSessionDesc;
+ lpNSCache lpCache = (lpNSCache)lpNSInfo;
+
+ /* Test for end of the list */
+ if( lpCache->present == NULL )
+ {
+ return NULL;
+ }
+
+ lpSessionDesc = lpCache->present->data;
+
+ /* Advance tracking pointer */
+ lpCache->present = lpCache->present->next;
+
+ return lpSessionDesc;
+}
diff --git a/dlls/dplayx/name_server.h b/dlls/dplayx/name_server.h
index b0404d6..33c27ac 100644
--- a/dlls/dplayx/name_server.h
+++ b/dlls/dplayx/name_server.h
@@ -4,6 +4,13 @@
#include "dplay.h"
-void DPLAYX_NS_SetLocalComputerAsNameServer( LPDPSESSIONDESC2 lpsd );
+void NS_SetLocalComputerAsNameServer( LPCDPSESSIONDESC2 lpsd );
+void NS_SendSessionRequestBroadcast( LPVOID lpNSInfo );
+
+BOOL NS_InitializeSessionCache( LPVOID* lplpNSInfo );
+void NS_DeleteSessionCache( LPVOID lpNSInfo );
+
+void NS_ResetSessionEnumeration( LPVOID lpNSInfo );
+LPDPSESSIONDESC2 NS_WalkSessions( LPVOID lpNSInfo );
#endif /* __WINE_DPLAYX_NAMESERVER */