1 /* DPLAYX.DLL name server implementation
3 * Copyright 2000 - Peter Hunnisett
5 * <presently under construction - contact hunnise@nortelnetworks.com>
9 /* NOTE: Methods with the NS_ prefix are name server methods */
12 #include "debugtools.h"
16 #include "dplayx_global.h"
17 #include "name_server.h"
19 #include "dplayx_messages.h"
20 #include "dplayx_queue.h"
22 /* FIXME: Need to create a crit section, store and use it */
24 DEFAULT_DEBUG_CHANNEL(dplay);
26 /* NS specific structures */
29 DPQ_ENTRY(NSCacheData) next;
31 DWORD dwTime; /* Time at which data was last known valid */
32 LPDPSESSIONDESC2 data;
37 typedef struct NSCacheData NSCacheData, *lpNSCacheData;
41 lpNSCacheData present; /* keep track of what is to be looked at when walking */
43 DPQ_HEAD(NSCacheData) first;
45 typedef struct NSCache NSCache, *lpNSCache;
47 /* Function prototypes */
48 DPQ_DECL_DELETECB( cbDeleteNSNodeFromHeap, lpNSCacheData );
50 /* Name Server functions
51 * ---------------------
53 void NS_SetLocalComputerAsNameServer( LPCDPSESSIONDESC2 lpsd )
56 /* FIXME: Remove this method? */
57 DPLAYX_SetLocalSession( lpsd );
61 DPQ_DECL_COMPARECB( cbUglyPig, GUID )
63 return IsEqualGUID( elem1, elem2 );
66 /* Store the given NS remote address for future reference */
67 void NS_SetRemoteComputerAsNameServer( LPVOID lpNSAddrHdr,
69 LPDPMSG_ENUMSESSIONSREPLY lpMsg,
72 lpNSCache lpCache = (lpNSCache)lpNSInfo;
73 lpNSCacheData lpCacheNode;
75 TRACE( "%p, %p, %p\n", lpNSAddrHdr, lpMsg, lpNSInfo );
77 /* FIXME: Should check to see if the reply is for an existing session. If
78 * so we remove the old and add the new so oldest is at front.
81 /* See if we can find this session. If we can, remove it as it's a dup */
82 DPQ_REMOVE_ENTRY_CB( lpCache->first, next, data->guidInstance, cbUglyPig,
83 lpMsg->sd.guidInstance, lpCacheNode );
85 if( lpCacheNode != NULL )
87 TRACE( "Duplicate session entry for %s removed - updated version kept\n",
88 debugstr_guid( &lpCacheNode->data->guidInstance ) );
89 cbDeleteNSNodeFromHeap( lpCacheNode );
92 /* Add this to the list */
93 lpCacheNode = (lpNSCacheData)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
94 sizeof( *lpCacheNode ) );
96 if( lpCacheNode == NULL )
98 ERR( "no memory for NS node\n" );
102 lpCacheNode->lpNSAddrHdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
104 CopyMemory( lpCacheNode->lpNSAddrHdr, lpNSAddrHdr, dwHdrSize );
107 lpCacheNode->data = (LPDPSESSIONDESC2)HeapAlloc( GetProcessHeap(),
109 sizeof( *lpCacheNode->data ) );
111 if( lpCacheNode->data == NULL )
113 ERR( "no memory for SESSIONDESC2\n" );
117 CopyMemory( lpCacheNode->data, &lpMsg->sd, sizeof( *lpCacheNode->data ) );
118 lpCacheNode->data->sess.lpszSessionNameA = HEAP_strdupWtoA( GetProcessHeap(),
122 lpCacheNode->dwTime = timeGetTime();
124 DPQ_INSERT(lpCache->first, lpCacheNode, next );
126 lpCache->present = lpCacheNode;
128 /* Use this message as an oportunity to weed out any old sessions so
129 * that we don't enum them again
131 NS_PruneSessionCache( lpNSInfo );
134 LPVOID NS_GetNSAddr( LPVOID lpNSInfo )
136 lpNSCache lpCache = (lpNSCache)lpNSInfo;
138 FIXME( ":quick stub\n" );
140 /* Ok. Cheat and don't search for the correct stuff just take the first.
141 * FIXME: In the future how are we to know what is _THE_ enum we used?
142 * This is going to have to go into dplay somehow. Perhaps it
143 * comes back with app server id for the join command! Oh...that
144 * must be it. That would make this method obsolete once that's
148 return lpCache->first.lpQHFirst->lpNSAddrHdr;
151 /* This function is responsible for sending a request for all other known
152 nameservers to send us what sessions they have registered locally
154 HRESULT NS_SendSessionRequestBroadcast( LPCGUID lpcGuid,
156 LPSPINITDATA lpSpData )
159 DPSP_ENUMSESSIONSDATA data;
160 LPDPMSG_ENUMSESSIONSREQUEST lpMsg;
162 TRACE( "enumerating for guid %s\n", debugstr_guid( lpcGuid ) );
164 /* Get the SP to deal with sending the EnumSessions request */
165 FIXME( ": not all data fields are correct\n" );
167 data.dwMessageSize = lpSpData->dwSPHeaderSize + sizeof( *lpMsg ); /*FIXME!*/
168 data.lpMessage = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
169 data.dwMessageSize );
170 data.lpISP = lpSpData->lpISP;
171 data.bReturnStatus = (dwFlags & DPENUMSESSIONS_RETURNSTATUS) ? TRUE : FALSE;
174 lpMsg = (LPDPMSG_ENUMSESSIONSREQUEST)(((BYTE*)data.lpMessage)+lpSpData->dwSPHeaderSize);
176 /* Setup EnumSession reqest message */
177 lpMsg->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
178 lpMsg->envelope.wCommandId = DPMSGCMD_ENUMSESSIONSREQUEST;
179 lpMsg->envelope.wVersion = DPMSGVER_DP6;
181 lpMsg->dwPasswordSize = 0; /* FIXME: If enumerating passwords..? */
182 lpMsg->dwFlags = dwFlags;
184 CopyMemory( &lpMsg->guidApplication, lpcGuid, sizeof( *lpcGuid ) );
186 return (lpSpData->lpCB->EnumSessions)( &data );
189 /* Delete a name server node which has been allocated on the heap */
190 DPQ_DECL_DELETECB( cbDeleteNSNodeFromHeap, lpNSCacheData )
192 /* NOTE: This proc doesn't deal with the walking pointer */
194 /* FIXME: Memory leak on data (contained ptrs) */
195 HeapFree( GetProcessHeap(), 0, elem->data );
196 HeapFree( GetProcessHeap(), 0, elem->lpNSAddrHdr );
197 HeapFree( GetProcessHeap(), 0, elem );
200 /* Render all data in a session cache invalid */
201 void NS_InvalidateSessionCache( LPVOID lpNSInfo )
203 lpNSCache lpCache = (lpNSCache)lpNSInfo;
205 if( lpCache == NULL )
207 ERR( ": invalidate non existant cache\n" );
211 DPQ_DELETEQ( lpCache->first, next, lpNSCacheData, cbDeleteNSNodeFromHeap );
213 /* NULL out the walking pointer */
214 lpCache->present = NULL;
217 /* Create and initialize a session cache */
218 BOOL NS_InitializeSessionCache( LPVOID* lplpNSInfo )
220 lpNSCache lpCache = (lpNSCache)HeapAlloc( GetProcessHeap(),
222 sizeof( *lpCache ) );
224 *lplpNSInfo = lpCache;
226 if( lpCache == NULL )
231 DPQ_INIT(lpCache->first);
232 lpCache->present = NULL;
237 /* Delete a session cache */
238 void NS_DeleteSessionCache( LPVOID lpNSInfo )
240 NS_InvalidateSessionCache( (lpNSCache)lpNSInfo );
243 /* Reinitialize the present pointer for this cache */
244 void NS_ResetSessionEnumeration( LPVOID lpNSInfo )
246 ((lpNSCache)lpNSInfo)->present = ((lpNSCache)lpNSInfo)->first.lpQHFirst;
249 LPDPSESSIONDESC2 NS_WalkSessions( LPVOID lpNSInfo )
251 LPDPSESSIONDESC2 lpSessionDesc;
252 lpNSCache lpCache = (lpNSCache)lpNSInfo;
254 /* FIXME: The pointers could disappear when walking if a prune happens */
256 /* Test for end of the list */
257 if( lpCache->present == NULL )
262 lpSessionDesc = lpCache->present->data;
264 /* Advance tracking pointer */
265 lpCache->present = lpCache->present->next.lpQNext;
267 return lpSessionDesc;
270 /* This method should check to see if there are any sessions which are
271 * older than the criteria. If so, just delete that information.
273 /* FIXME: This needs to be called by some periodic timer */
274 void NS_PruneSessionCache( LPVOID lpNSInfo )
276 lpNSCache lpCache = lpNSInfo;
278 const DWORD dwPresentTime = timeGetTime();
279 const DWORD dwPrunePeriod = 60000; /* is 60 secs enough? */
280 const DWORD dwPruneTime = dwPresentTime - dwPrunePeriod;
282 /* This silly little algorithm is based on the fact we keep entries in
283 * the queue in a time based order. It also assumes that it is not possible
284 * to wrap around over yourself (which is not unreasonable).
285 * The if statements verify if the first entry in the queue is less
286 * than dwPrunePeriod old depending on the "clock" roll over.
290 lpNSCacheData lpFirstData;
292 if( DPQ_IS_EMPTY(lpCache->first) )
294 /* Nothing to prune */
298 if( dwPruneTime > dwPresentTime ) /* 0 <= dwPresentTime <= dwPrunePeriod */
300 if( ( DPQ_FIRST(lpCache->first)->dwTime <= dwPresentTime ) ||
301 ( DPQ_FIRST(lpCache->first)->dwTime > dwPruneTime )
304 /* Less than dwPrunePeriod old - keep */
308 else /* dwPrunePeriod <= dwPresentTime <= max dword */
310 if( ( DPQ_FIRST(lpCache->first)->dwTime <= dwPresentTime ) &&
311 ( DPQ_FIRST(lpCache->first)->dwTime > dwPruneTime )
314 /* Less than dwPrunePeriod old - keep */
319 lpFirstData = DPQ_FIRST(lpCache->first);
320 DPQ_REMOVE( lpCache->first, DPQ_FIRST(lpCache->first), next );
321 cbDeleteNSNodeFromHeap( lpFirstData );
326 /* NAME SERVER Message stuff */
327 void NS_ReplyToEnumSessionsRequest( LPVOID lpMsg,
328 LPDPSP_REPLYDATA lpReplyData,
329 IDirectPlay2Impl* lpDP )
331 LPDPMSG_ENUMSESSIONSREPLY rmsg;
332 DWORD dwVariableSize;
335 /* LPDPMSG_ENUMSESSIONSREQUEST msg = (LPDPMSG_ENUMSESSIONSREQUEST)lpMsg; */
336 BOOL bAnsi = TRUE; /* FIXME: This needs to be in the DPLAY interface */
338 FIXME( ": few fixed + need to check request for response\n" );
340 dwVariableLen = bAnsi ? lstrlenA( lpDP->dp2->lpSessionDesc->sess.lpszSessionNameA ) + 1
341 : lstrlenW( lpDP->dp2->lpSessionDesc->sess.lpszSessionName ) + 1;
343 dwVariableSize = dwVariableLen * sizeof( WCHAR );
345 lpReplyData->dwMessageSize = lpDP->dp2->spData.dwSPHeaderSize +
346 sizeof( *rmsg ) + dwVariableSize;
347 lpReplyData->lpMessage = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
348 lpReplyData->dwMessageSize );
350 rmsg = (LPDPMSG_ENUMSESSIONSREPLY)( (BYTE*)lpReplyData->lpMessage +
351 lpDP->dp2->spData.dwSPHeaderSize);
353 rmsg->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
354 rmsg->envelope.wCommandId = DPMSGCMD_ENUMSESSIONSREPLY;
355 rmsg->envelope.wVersion = DPMSGVER_DP6;
357 CopyMemory( &rmsg->sd, lpDP->dp2->lpSessionDesc,
358 sizeof( lpDP->dp2->lpSessionDesc->dwSize ) );
359 rmsg->dwUnknown = 0x0000005c;
362 string = HEAP_strdupAtoW( GetProcessHeap(), 0,
363 lpDP->dp2->lpSessionDesc->sess.lpszSessionNameA );
364 /* FIXME: Memory leak */
368 string = lpDP->dp2->lpSessionDesc->sess.lpszSessionName;
371 lstrcpyW( (LPWSTR)(rmsg+1), string );