source: trunk/src/DPlayX/name_server.cpp

Last change on this file was 21494, checked in by dmik, 15 years ago

Fixed broken build after r21492 by sorting out a huuuuge wagon of duplicates, wrong include order and other dirty mess.

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