source: trunk/src/DPlayX/name_server.cpp@ 10367

Last change on this file since 10367 was 5526, checked in by sandervl, 24 years ago

compile fixes

File size: 11.4 KB
Line 
1// $Id: name_server.cpp,v 1.5 2001-04-16 17:25:26 sandervl Exp $
2/* DPLAYX.DLL name server implementation
3 *
4 * Copyright 2000 - Peter Hunnisett
5 *
6 * <presently under construction - contact hunnise@nortelnetworks.com>
7 *
8 */
9
10/* NOTE: Methods with the NS_ prefix are name server methods */
11
12#include <string.h>
13
14#include <odin.h>
15#define ICOM_CINTERFACE 1
16#define CINTERFACE
17
18#include "winbase.h"
19#include "winuser.h"
20#include "winnls.h"
21#include "wine/unicode.h"
22#include "debugtools.h"
23#include "heap.h"
24#include "heapstring.h"
25#include "mmsystem.h"
26
27#include "dplayx_global.h"
28#include "name_server.h"
29#include "dplaysp.h"
30#include "dplayx_messages.h"
31#include "dplayx_queue.h"
32
33/* FIXME: Need to create a crit section, store and use it */
34
35DEFAULT_DEBUG_CHANNEL(dplay);
36
37#undef debugstr_guid
38#define debugstr_guid(a) a
39
40/* NS specific structures */
41struct NSCacheData
42{
43 DPQ_ENTRY(NSCacheData) next;
44
45 DWORD dwTime; /* Time at which data was last known valid */
46 LPDPSESSIONDESC2 data;
47
48 LPVOID lpNSAddrHdr;
49
50};
51typedef struct NSCacheData NSCacheData, *lpNSCacheData;
52
53struct NSCache
54{
55 lpNSCacheData present; /* keep track of what is to be looked at when walking */
56
57 DPQ_HEAD(NSCacheData) first;
58};
59typedef struct NSCache NSCache, *lpNSCache;
60
61/* Function prototypes */
62DPQ_DECL_DELETECB( cbDeleteNSNodeFromHeap, lpNSCacheData );
63
64/* Name Server functions
65 * ---------------------
66 */
67void NS_SetLocalComputerAsNameServer( LPCDPSESSIONDESC2 lpsd )
68{
69#if 0
70 /* FIXME: Remove this method? */
71 DPLAYX_SetLocalSession( lpsd );
72#endif
73}
74
75DPQ_DECL_COMPARECB( cbUglyPig, GUID )
76{
77 return IsEqualGUID( elem1, elem2 );
78}
79
80/* Store the given NS remote address for future reference */
81void NS_SetRemoteComputerAsNameServer( LPVOID lpNSAddrHdr,
82 DWORD dwHdrSize,
83 LPDPMSG_ENUMSESSIONSREPLY lpMsg,
84 LPVOID lpNSInfo )
85{
86 DWORD len;
87 lpNSCache lpCache = (lpNSCache)lpNSInfo;
88 lpNSCacheData lpCacheNode;
89
90 TRACE( "%p, %p, %p\n", lpNSAddrHdr, lpMsg, lpNSInfo );
91
92 /* FIXME: Should check to see if the reply is for an existing session. If
93 * so we remove the old and add the new so oldest is at front.
94 */
95
96 /* See if we can find this session. If we can, remove it as it's a dup */
97 DPQ_REMOVE_ENTRY_CB( lpCache->first, next, data->guidInstance, cbUglyPig,
98 lpMsg->sd.guidInstance, lpCacheNode );
99
100 if( lpCacheNode != NULL )
101 {
102 TRACE( "Duplicate session entry for %s removed - updated version kept\n",
103 debugstr_guid( &lpCacheNode->data->guidInstance ) );
104 cbDeleteNSNodeFromHeap( lpCacheNode );
105 }
106
107 /* Add this to the list */
108 lpCacheNode = (lpNSCacheData)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
109 sizeof( *lpCacheNode ) );
110
111 if( lpCacheNode == NULL )
112 {
113 ERR( "no memory for NS node\n" );
114 return;
115 }
116
117 lpCacheNode->lpNSAddrHdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
118 dwHdrSize );
119 CopyMemory( lpCacheNode->lpNSAddrHdr, lpNSAddrHdr, dwHdrSize );
120
121
122 lpCacheNode->data = (LPDPSESSIONDESC2)HeapAlloc( GetProcessHeap(),
123 HEAP_ZERO_MEMORY,
124 sizeof( *lpCacheNode->data ) );
125
126 if( lpCacheNode->data == NULL )
127 {
128 ERR( "no memory for SESSIONDESC2\n" );
129 return;
130 }
131
132 CopyMemory( lpCacheNode->data, &lpMsg->sd, sizeof( *lpCacheNode->data ) );
133 len = WideCharToMultiByte( CP_ACP, 0, (LPWSTR)(lpMsg+1), -1, NULL, 0, NULL, NULL );
134 if ((lpCacheNode->data->lpszSessionNameA = (LPSTR)HeapAlloc( GetProcessHeap(), 0, len )))
135 WideCharToMultiByte( CP_ACP, 0, (LPWSTR)(lpMsg+1), -1,
136 lpCacheNode->data->lpszSessionNameA, len, NULL, NULL );
137
138 lpCacheNode->dwTime = timeGetTime();
139
140 DPQ_INSERT(lpCache->first, lpCacheNode, next );
141
142 lpCache->present = lpCacheNode;
143
144 /* Use this message as an oportunity to weed out any old sessions so
145 * that we don't enum them again
146 */
147 NS_PruneSessionCache( lpNSInfo );
148}
149
150LPVOID NS_GetNSAddr( LPVOID lpNSInfo )
151{
152 lpNSCache lpCache = (lpNSCache)lpNSInfo;
153
154 FIXME( ":quick stub\n" );
155
156 /* Ok. Cheat and don't search for the correct stuff just take the first.
157 * FIXME: In the future how are we to know what is _THE_ enum we used?
158 * This is going to have to go into dplay somehow. Perhaps it
159 * comes back with app server id for the join command! Oh...that
160 * must be it. That would make this method obsolete once that's
161 * in place.
162 */
163
164 return lpCache->first.lpQHFirst->lpNSAddrHdr;
165}
166
167/* This function is responsible for sending a request for all other known
168 nameservers to send us what sessions they have registered locally
169 */
170HRESULT NS_SendSessionRequestBroadcast( LPCGUID lpcGuid,
171 DWORD dwFlags,
172 LPSPINITDATA lpSpData )
173
174{
175 DPSP_ENUMSESSIONSDATA data;
176 LPDPMSG_ENUMSESSIONSREQUEST lpMsg;
177
178 TRACE( "enumerating for guid %s\n", debugstr_guid( lpcGuid ) );
179
180 /* Get the SP to deal with sending the EnumSessions request */
181 FIXME( ": not all data fields are correct\n" );
182
183 data.dwMessageSize = lpSpData->dwSPHeaderSize + sizeof( *lpMsg ); /*FIXME!*/
184 data.lpMessage = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
185 data.dwMessageSize );
186 data.lpISP = lpSpData->lpISP;
187 data.bReturnStatus = (dwFlags & DPENUMSESSIONS_RETURNSTATUS) ? TRUE : FALSE;
188
189
190 lpMsg = (LPDPMSG_ENUMSESSIONSREQUEST)(((BYTE*)data.lpMessage)+lpSpData->dwSPHeaderSize);
191
192 /* Setup EnumSession reqest message */
193 lpMsg->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
194 lpMsg->envelope.wCommandId = DPMSGCMD_ENUMSESSIONSREQUEST;
195 lpMsg->envelope.wVersion = DPMSGVER_DP6;
196
197 lpMsg->dwPasswordSize = 0; /* FIXME: If enumerating passwords..? */
198 lpMsg->dwFlags = dwFlags;
199
200 CopyMemory( &lpMsg->guidApplication, lpcGuid, sizeof( *lpcGuid ) );
201
202 return (lpSpData->lpCB->EnumSessions)( &data );
203}
204
205/* Delete a name server node which has been allocated on the heap */
206DPQ_DECL_DELETECB( cbDeleteNSNodeFromHeap, lpNSCacheData )
207{
208 /* NOTE: This proc doesn't deal with the walking pointer */
209
210 /* FIXME: Memory leak on data (contained ptrs) */
211 HeapFree( GetProcessHeap(), 0, elem->data );
212 HeapFree( GetProcessHeap(), 0, elem->lpNSAddrHdr );
213 HeapFree( GetProcessHeap(), 0, elem );
214}
215
216/* Render all data in a session cache invalid */
217void NS_InvalidateSessionCache( LPVOID lpNSInfo )
218{
219 lpNSCache lpCache = (lpNSCache)lpNSInfo;
220
221 if( lpCache == NULL )
222 {
223 ERR( ": invalidate non existant cache\n" );
224 return;
225 }
226
227 DPQ_DELETEQ( lpCache->first, next, lpNSCacheData, cbDeleteNSNodeFromHeap );
228
229 /* NULL out the walking pointer */
230 lpCache->present = NULL;
231}
232
233/* Create and initialize a session cache */
234BOOL NS_InitializeSessionCache( LPVOID* lplpNSInfo )
235{
236 lpNSCache lpCache = (lpNSCache)HeapAlloc( GetProcessHeap(),
237 HEAP_ZERO_MEMORY,
238 sizeof( *lpCache ) );
239
240 *lplpNSInfo = lpCache;
241
242 if( lpCache == NULL )
243 {
244 return FALSE;
245 }
246
247 DPQ_INIT(lpCache->first);
248 lpCache->present = NULL;
249
250 return TRUE;
251}
252
253/* Delete a session cache */
254void NS_DeleteSessionCache( LPVOID lpNSInfo )
255{
256 NS_InvalidateSessionCache( (lpNSCache)lpNSInfo );
257}
258
259/* Reinitialize the present pointer for this cache */
260void NS_ResetSessionEnumeration( LPVOID lpNSInfo )
261{
262 ((lpNSCache)lpNSInfo)->present = ((lpNSCache)lpNSInfo)->first.lpQHFirst;
263}
264
265LPDPSESSIONDESC2 NS_WalkSessions( LPVOID lpNSInfo )
266{
267 LPDPSESSIONDESC2 lpSessionDesc;
268 lpNSCache lpCache = (lpNSCache)lpNSInfo;
269
270 /* FIXME: The pointers could disappear when walking if a prune happens */
271
272 /* Test for end of the list */
273 if( lpCache->present == NULL )
274 {
275 return NULL;
276 }
277
278 lpSessionDesc = lpCache->present->data;
279
280 /* Advance tracking pointer */
281 lpCache->present = lpCache->present->next.lpQNext;
282
283 return lpSessionDesc;
284}
285
286/* This method should check to see if there are any sessions which are
287 * older than the criteria. If so, just delete that information.
288 */
289/* FIXME: This needs to be called by some periodic timer */
290void NS_PruneSessionCache( LPVOID lpNSInfo )
291{
292 lpNSCache lpCache = (lpNSCache)lpNSInfo;
293
294 const DWORD dwPresentTime = timeGetTime();
295 const DWORD dwPrunePeriod = 60000; /* is 60 secs enough? */
296 const DWORD dwPruneTime = dwPresentTime - dwPrunePeriod;
297
298 /* This silly little algorithm is based on the fact we keep entries in
299 * the queue in a time based order. It also assumes that it is not possible
300 * to wrap around over yourself (which is not unreasonable).
301 * The if statements verify if the first entry in the queue is less
302 * than dwPrunePeriod old depending on the "clock" roll over.
303 */
304 for( ;; )
305 {
306 lpNSCacheData lpFirstData;
307
308 if( DPQ_IS_EMPTY(lpCache->first) )
309 {
310 /* Nothing to prune */
311 break;
312 }
313
314 if( dwPruneTime > dwPresentTime ) /* 0 <= dwPresentTime <= dwPrunePeriod */
315 {
316 if( ( DPQ_FIRST(lpCache->first)->dwTime <= dwPresentTime ) ||
317 ( DPQ_FIRST(lpCache->first)->dwTime > dwPruneTime )
318 )
319 {
320 /* Less than dwPrunePeriod old - keep */
321 break;
322 }
323 }
324 else /* dwPrunePeriod <= dwPresentTime <= max dword */
325 {
326 if( ( DPQ_FIRST(lpCache->first)->dwTime <= dwPresentTime ) &&
327 ( DPQ_FIRST(lpCache->first)->dwTime > dwPruneTime )
328 )
329 {
330 /* Less than dwPrunePeriod old - keep */
331 break;
332 }
333 }
334
335 lpFirstData = DPQ_FIRST(lpCache->first);
336 DPQ_REMOVE( lpCache->first, DPQ_FIRST(lpCache->first), next );
337 cbDeleteNSNodeFromHeap( lpFirstData );
338 }
339
340}
341
342/* NAME SERVER Message stuff */
343void NS_ReplyToEnumSessionsRequest( LPVOID lpMsg,
344 LPDPSP_REPLYDATA lpReplyData,
345 IDirectPlay2Impl* lpDP )
346{
347 LPDPMSG_ENUMSESSIONSREPLY rmsg;
348 DWORD dwVariableSize;
349 DWORD dwVariableLen;
350 /* LPDPMSG_ENUMSESSIONSREQUEST msg = (LPDPMSG_ENUMSESSIONSREQUEST)lpMsg; */
351 BOOL bAnsi = TRUE; /* FIXME: This needs to be in the DPLAY interface */
352
353 FIXME( ": few fixed + need to check request for response\n" );
354
355 if (bAnsi)
356 dwVariableLen = MultiByteToWideChar( CP_ACP, 0,
357 lpDP->dp2->lpSessionDesc->lpszSessionNameA,
358 -1, NULL, 0 );
359 else
360 dwVariableLen = strlenW( lpDP->dp2->lpSessionDesc->lpszSessionName ) + 1;
361
362 dwVariableSize = dwVariableLen * sizeof( WCHAR );
363
364 lpReplyData->dwMessageSize = lpDP->dp2->spData.dwSPHeaderSize +
365 sizeof( *rmsg ) + dwVariableSize;
366 lpReplyData->lpMessage = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
367 lpReplyData->dwMessageSize );
368
369 rmsg = (LPDPMSG_ENUMSESSIONSREPLY)( (BYTE*)lpReplyData->lpMessage +
370 lpDP->dp2->spData.dwSPHeaderSize);
371
372 rmsg->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
373 rmsg->envelope.wCommandId = DPMSGCMD_ENUMSESSIONSREPLY;
374 rmsg->envelope.wVersion = DPMSGVER_DP6;
375
376 CopyMemory( &rmsg->sd, lpDP->dp2->lpSessionDesc,
377 sizeof( lpDP->dp2->lpSessionDesc->dwSize ) );
378 rmsg->dwUnknown = 0x0000005c;
379 if( bAnsi )
380 MultiByteToWideChar( CP_ACP, 0, lpDP->dp2->lpSessionDesc->lpszSessionNameA, -1,
381 (LPWSTR)(rmsg+1), dwVariableLen );
382 else
383 strcpyW( (LPWSTR)(rmsg+1), lpDP->dp2->lpSessionDesc->lpszSessionName );
384}
Note: See TracBrowser for help on using the repository browser.