source: trunk/src/DPlayX/dplayx_messages.cpp@ 6666

Last change on this file since 6666 was 5311, checked in by hugh, 24 years ago

Synced with WINE

File size: 14.7 KB
Line 
1// $Id: dplayx_messages.cpp,v 1.4 2001-03-13 23:13:27 hugh Exp $
2/* DirectPlay & DirectPlayLobby messaging implementation
3 *
4 * Copyright 2000 - Peter Hunnisett
5 *
6 * <presently under construction - contact hunnise@nortelnetworks.com>
7 *
8 */
9#include <string.h>
10
11#include <odin.h>
12#define ICOM_CINTERFACE 1
13#define CINTERFACE
14
15#include "winbase.h"
16#include "debugtools.h"
17
18#include "wingdi.h"
19#include "winuser.h"
20#include "winerror.h"
21
22#include "dplayx_messages.h"
23#include "dplay_global.h"
24#include "dplayx_global.h"
25
26DEFAULT_DEBUG_CHANNEL(dplay);
27
28#undef debugstr_guid
29#define debugstr_guid(a) a
30
31typedef struct tagMSGTHREADINFO
32{
33 HANDLE hStart;
34 HANDLE hDeath;
35 HANDLE hSettingRead;
36 HANDLE hNotifyEvent;
37} MSGTHREADINFO, *LPMSGTHREADINFO;
38
39
40static DWORD CALLBACK DPL_MSG_ThreadMain( LPVOID lpContext );
41static LPVOID DP_MSG_ExpectReply( IDirectPlay2AImpl* This, LPDPSP_SENDDATA data,
42 DWORD dwWaitTime, WORD wReplyCommandId,
43 LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize );
44
45/* Create the message reception thread to allow the application to receive
46 * asynchronous message reception
47 */
48DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart,
49 HANDLE hDeath, HANDLE hConnRead )
50{
51 DWORD dwMsgThreadId;
52 LPMSGTHREADINFO lpThreadInfo;
53
54 lpThreadInfo = (LPMSGTHREADINFO) HeapAlloc( GetProcessHeap(), 0, sizeof( *lpThreadInfo ) );
55 if( lpThreadInfo == NULL )
56 {
57 return 0;
58 }
59
60 /* The notify event may or may not exist. Depends if async comm or not */
61 if( hNotifyEvent &&
62 !DuplicateHandle( GetCurrentProcess(), hNotifyEvent,
63 GetCurrentProcess(), &lpThreadInfo->hNotifyEvent,
64 0, FALSE, DUPLICATE_SAME_ACCESS ) )
65 {
66 ERR( "Unable to duplicate event handle\n" );
67 goto error;
68 }
69
70 /* These 3 handles don't need to be duplicated because we don't keep a
71 * reference to them where they're created. They're created specifically
72 * for the message thread
73 */
74 lpThreadInfo->hStart = hStart;
75 lpThreadInfo->hDeath = hDeath;
76 lpThreadInfo->hSettingRead = hConnRead;
77
78 if( !CreateThread( NULL, /* Security attribs */
79 0, /* Stack */
80 DPL_MSG_ThreadMain, /* Msg reception function */
81 lpThreadInfo, /* Msg reception func parameter */
82 0, /* Flags */
83 &dwMsgThreadId /* Updated with thread id */
84 )
85 )
86 {
87 ERR( "Unable to create msg thread\n" );
88 goto error;
89 }
90
91 /* FIXME: Should I be closing the handle to the thread or does that
92 terminate the thread? */
93
94 return dwMsgThreadId;
95
96error:
97
98 HeapFree( GetProcessHeap(), 0, lpThreadInfo );
99
100 return 0;
101}
102
103static DWORD CALLBACK DPL_MSG_ThreadMain( LPVOID lpContext )
104{
105 LPMSGTHREADINFO lpThreadInfo = (LPMSGTHREADINFO)lpContext;
106 DWORD dwWaitResult;
107
108 TRACE( "Msg thread created. Waiting on app startup\n" );
109
110 /* Wait to ensure that the lobby application is started w/ 1 min timeout */
111 dwWaitResult = WaitForSingleObject( lpThreadInfo->hStart, 10000 /* 10 sec */ );
112 if( dwWaitResult == WAIT_TIMEOUT )
113 {
114 FIXME( "Should signal app/wait creation failure (0x%08lx)\n", dwWaitResult );
115 goto end_of_thread;
116 }
117
118 /* Close this handle as it's not needed anymore */
119 CloseHandle( lpThreadInfo->hStart );
120 lpThreadInfo->hStart = 0;
121
122 /* Wait until the lobby knows what it is */
123 dwWaitResult = WaitForSingleObject( lpThreadInfo->hSettingRead, INFINITE );
124 if( dwWaitResult == WAIT_TIMEOUT )
125 {
126 ERR( "App Read connection setting timeout fail (0x%08lx)\n", dwWaitResult );
127 }
128
129 /* Close this handle as it's not needed anymore */
130 CloseHandle( lpThreadInfo->hSettingRead );
131 lpThreadInfo->hSettingRead = 0;
132
133 TRACE( "App created && intialized starting main message reception loop\n" );
134
135 for ( ;; )
136 {
137 MSG lobbyMsg;
138 GetMessageW( &lobbyMsg, 0, 0, 0 );
139 }
140
141end_of_thread:
142 TRACE( "Msg thread exiting!\n" );
143 HeapFree( GetProcessHeap(), 0, lpThreadInfo );
144
145 return 0;
146}
147
148/* DP messageing stuff */
149static HANDLE DP_MSG_BuildAndLinkReplyStruct( IDirectPlay2Impl* This,
150 LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList,
151 WORD wReplyCommandId );
152static LPVOID DP_MSG_CleanReplyStruct( LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList,
153 LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize );
154
155
156static
157HANDLE DP_MSG_BuildAndLinkReplyStruct( IDirectPlay2Impl* This,
158 LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList, WORD wReplyCommandId )
159{
160 lpReplyStructList->replyExpected.hReceipt = CreateEventA( NULL, FALSE, FALSE, NULL );
161 lpReplyStructList->replyExpected.wExpectedReply = wReplyCommandId;
162 lpReplyStructList->replyExpected.lpReplyMsg = NULL;
163 lpReplyStructList->replyExpected.dwMsgBodySize = 0;
164
165 /* Insert into the message queue while locked */
166 EnterCriticalSection( &This->unk->DP_lock );
167 DPQ_INSERT( This->dp2->replysExpected, lpReplyStructList, replysExpected );
168 LeaveCriticalSection( &This->unk->DP_lock );
169
170 return lpReplyStructList->replyExpected.hReceipt;
171}
172
173static
174LPVOID DP_MSG_CleanReplyStruct( LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList,
175 LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize )
176{
177 CloseHandle( lpReplyStructList->replyExpected.hReceipt );
178
179 *lplpReplyMsg = lpReplyStructList->replyExpected.lpReplyMsg;
180 *lpdwMsgBodySize = lpReplyStructList->replyExpected.dwMsgBodySize;
181
182 return lpReplyStructList->replyExpected.lpReplyMsg;
183}
184
185HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags,
186 LPDPID lpdpidAllocatedId )
187{
188 LPVOID lpMsg;
189 LPDPMSG_REQUESTNEWPLAYERID lpMsgBody;
190 DWORD dwMsgSize;
191 HRESULT hr = DP_OK;
192
193 dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody );
194
195 lpMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwMsgSize );
196
197 lpMsgBody = (LPDPMSG_REQUESTNEWPLAYERID)( (BYTE*)lpMsg +
198 This->dp2->spData.dwSPHeaderSize );
199
200 /* Compose dplay message envelope */
201 lpMsgBody->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
202 lpMsgBody->envelope.wCommandId = DPMSGCMD_REQUESTNEWPLAYERID;
203 lpMsgBody->envelope.wVersion = DPMSGVER_DP6;
204
205 /* Compose the body of the message */
206 lpMsgBody->dwFlags = dwFlags;
207
208 /* Send the message */
209 {
210 DPSP_SENDDATA data;
211
212 data.dwFlags = DPSEND_GUARANTEED;
213 data.idPlayerTo = 0; /* Name server */
214 data.idPlayerFrom = 0; /* Sending from DP */
215 data.lpMessage = lpMsg;
216 data.dwMessageSize = dwMsgSize;
217 data.bSystemMessage = TRUE; /* Allow reply to be sent */
218 data.lpISP = This->dp2->spData.lpISP;
219
220 TRACE( "Asking for player id w/ dwFlags 0x%08lx\n",
221 lpMsgBody->dwFlags );
222
223
224 DP_MSG_ExpectReply( This, &data, DPMSG_DEFAULT_WAIT_TIME, DPMSGCMD_NEWPLAYERIDREPLY,
225 &lpMsg, &dwMsgSize );
226
227 }
228
229
230 /* Need to examine the data and extract the new player id */
231 if( !FAILED(hr) )
232 {
233 LPCDPMSG_NEWPLAYERIDREPLY lpcReply;
234
235 lpcReply = (LPCDPMSG_NEWPLAYERIDREPLY)lpMsg;
236
237 *lpdpidAllocatedId = lpcReply->dpidNewPlayerId;
238
239 TRACE( "Received reply for id = 0x%08lx\n", lpcReply->dpidNewPlayerId );
240
241 /* FIXME: I think that the rest of the message has something to do
242 * with remote data for the player that perhaps I need to setup.
243 * However, with the information that is passed, all that it could
244 * be used for is a standardized intialization value, which I'm
245 * guessing we can do without. Unless the message content is the same
246 * for several different messages?
247 */
248
249 HeapFree( GetProcessHeap(), 0, lpMsg );
250 }
251
252 return hr;
253}
254
255HRESULT DP_MSG_ForwardPlayerCreation( IDirectPlay2AImpl* This, DPID dpidServer )
256{
257 LPVOID lpMsg;
258 LPDPMSG_FORWARDADDPLAYER lpMsgBody;
259 DWORD dwMsgSize;
260 HRESULT hr = DP_OK;
261
262 dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody );
263
264 lpMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwMsgSize );
265
266 lpMsgBody = (LPDPMSG_FORWARDADDPLAYER)( (BYTE*)lpMsg +
267 This->dp2->spData.dwSPHeaderSize );
268
269 /* Compose dplay message envelope */
270 lpMsgBody->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
271 lpMsgBody->envelope.wCommandId = DPMSGCMD_FORWARDADDPLAYER;
272 lpMsgBody->envelope.wVersion = DPMSGVER_DP6;
273
274#if 0
275 {
276 LPBYTE lpPData;
277 DWORD dwDataSize;
278
279 /* SP Player remote data needs to be propagated at some point - is this the point? */
280 IDirectPlaySP_GetSPPlayerData( This->dp2->spData.lpISP, dpidServer, (LPVOID*)&lpPData, &dwDataSize, DPSET_REMOTE );
281
282 ERR( "Player Data size is 0x%08lx\n"
283 "[%02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x]\n"
284 "[%02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x]\n",
285
286 dwDataSize,
287 lpPData[0], lpPData[1], lpPData[2], lpPData[3], lpPData[4],
288 lpPData[5], lpPData[6], lpPData[7], lpPData[8], lpPData[9],
289 lpPData[10], lpPData[11], lpPData[12], lpPData[13], lpPData[14],
290 lpPData[15], lpPData[16], lpPData[17], lpPData[18], lpPData[19],
291 lpPData[20], lpPData[21], lpPData[22], lpPData[23], lpPData[24],
292 lpPData[25], lpPData[26], lpPData[27], lpPData[28], lpPData[29],
293 lpPData[30], lpPData[31]
294 );
295 DebugBreak();
296 }
297#endif
298
299 /* Compose body of message */
300 lpMsgBody->dpidAppServer = dpidServer;
301 lpMsgBody->unknown2[0] = 0x0;
302 lpMsgBody->unknown2[1] = 0x1c;
303 lpMsgBody->unknown2[2] = 0x6c;
304 lpMsgBody->unknown2[3] = 0x50;
305 lpMsgBody->unknown2[4] = 0x9;
306
307 lpMsgBody->dpidAppServer2 = dpidServer;
308 lpMsgBody->unknown3[0] = 0x0;
309 lpMsgBody->unknown3[0] = 0x0;
310 lpMsgBody->unknown3[0] = 0x20;
311 lpMsgBody->unknown3[0] = 0x0;
312 lpMsgBody->unknown3[0] = 0x0;
313
314 lpMsgBody->dpidAppServer3 = dpidServer;
315 lpMsgBody->unknown4[0] = 0x30;
316 lpMsgBody->unknown4[1] = 0xb;
317 lpMsgBody->unknown4[2] = 0x0;
318 lpMsgBody->unknown4[3] = 0x1e090002;
319 lpMsgBody->unknown4[4] = 0x0;
320 lpMsgBody->unknown4[5] = 0x0;
321 lpMsgBody->unknown4[6] = 0x0;
322 lpMsgBody->unknown4[7] = 0x32090002;
323 lpMsgBody->unknown4[8] = 0x0;
324 lpMsgBody->unknown4[9] = 0x0;
325 lpMsgBody->unknown4[10] = 0x0;
326 lpMsgBody->unknown4[11] = 0x0;
327 lpMsgBody->unknown4[12] = 0x0;
328
329 lpMsgBody->unknown5[0] = 0x0;
330 lpMsgBody->unknown5[1] = 0x0;
331
332 /* Send the message */
333 {
334 DPSP_SENDDATA data;
335
336 data.dwFlags = DPSEND_GUARANTEED;
337 data.idPlayerTo = 0; /* Name server */
338 data.idPlayerFrom = dpidServer; /* Sending from session server */
339 data.lpMessage = lpMsg;
340 data.dwMessageSize = dwMsgSize;
341 data.bSystemMessage = TRUE; /* Allow reply to be sent */
342 data.lpISP = This->dp2->spData.lpISP;
343
344 lpMsg = DP_MSG_ExpectReply( This, &data,
345 DPMSG_WAIT_60_SECS,
346 DPMSGCMD_GETNAMETABLEREPLY,
347 &lpMsg, &dwMsgSize );
348 }
349
350 /* Need to examine the data and extract the new player id */
351 if( lpMsg != NULL )
352 {
353 FIXME( "Name Table reply received: stub\n" );
354 }
355
356 return hr;
357}
358
359/* Queue up a structure indicating that we want a reply of type wReplyCommandId. DPlay does
360 * not seem to offer any way of uniquely differentiating between replies of the same type
361 * relative to the request sent. There is an implicit assumption that there will be no
362 * ordering issues on sends and receives from the opposite machine. No wonder MS is not
363 * a networking company.
364 */
365static
366LPVOID DP_MSG_ExpectReply( IDirectPlay2AImpl* This, LPDPSP_SENDDATA lpData,
367 DWORD dwWaitTime, WORD wReplyCommandId,
368 LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize )
369{
370 HRESULT hr;
371 HANDLE hMsgReceipt;
372 DP_MSG_REPLY_STRUCT_LIST replyStructList;
373 DWORD dwWaitReturn;
374
375 /* Setup for receipt */
376 hMsgReceipt = DP_MSG_BuildAndLinkReplyStruct( This, &replyStructList,
377 wReplyCommandId );
378
379 TRACE( "Sending msg and expecting cmd %u in reply within %lu ticks\n",
380 wReplyCommandId, dwWaitTime );
381 hr = (*This->dp2->spData.lpCB->Send)( lpData );
382
383 if( FAILED(hr) )
384 {
385 ERR( "Request for new playerID send failed: %s\n",
386 DPLAYX_HresultToString( hr ) );
387 return NULL;
388 }
389
390 dwWaitReturn = WaitForSingleObject( hMsgReceipt, dwWaitTime );
391 if( dwWaitReturn != WAIT_OBJECT_0 )
392 {
393 ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
394 return NULL;
395 }
396
397 /* Clean Up */
398 return DP_MSG_CleanReplyStruct( &replyStructList, lplpReplyMsg, lpdwMsgBodySize );
399}
400
401/* Determine if there is a matching request for this incomming message and then copy
402 * all important data. It is quite silly to have to copy the message, but the documents
403 * indicate that a copy is taken. Silly really.
404 */
405void DP_MSG_ReplyReceived( IDirectPlay2AImpl* This, WORD wCommandId,
406 LPCVOID lpcMsgBody, DWORD dwMsgBodySize )
407{
408 LPDP_MSG_REPLY_STRUCT_LIST lpReplyList;
409
410#if 0
411 if( wCommandId == DPMSGCMD_FORWARDADDPLAYER )
412 {
413 DebugBreak();
414 }
415#endif
416
417 /* Find, and immediately remove (to avoid double triggering), the appropriate entry. Call locked to
418 * avoid problems.
419 */
420 EnterCriticalSection( &This->unk->DP_lock );
421 DPQ_REMOVE_ENTRY( This->dp2->replysExpected, replysExpected, replyExpected.wExpectedReply,\
422 ==, wCommandId, lpReplyList );
423 LeaveCriticalSection( &This->unk->DP_lock );
424
425 if( lpReplyList != NULL )
426 {
427 lpReplyList->replyExpected.dwMsgBodySize = dwMsgBodySize;
428 lpReplyList->replyExpected.lpReplyMsg = HeapAlloc( GetProcessHeap(),
429 HEAP_ZERO_MEMORY,
430 dwMsgBodySize );
431 CopyMemory( lpReplyList->replyExpected.lpReplyMsg,
432 lpcMsgBody, dwMsgBodySize );
433
434 /* Signal the thread which sent the message that it has a reply */
435 SetEvent( lpReplyList->replyExpected.hReceipt );
436 }
437 else
438 {
439 ERR( "No receipt event set - only expecting in reply mode\n" );
440 DebugBreak();
441 }
442
443}
444
445void DP_MSG_ErrorReceived( IDirectPlay2AImpl* This, WORD wCommandId,
446 LPCVOID lpMsgBody, DWORD dwMsgBodySize )
447{
448 LPCDPMSG_FORWARDADDPLAYERNACK lpcErrorMsg;
449
450 lpcErrorMsg = (LPCDPMSG_FORWARDADDPLAYERNACK)lpMsgBody;
451
452 ERR( "Received error message %u. Error is %s\n",
453 wCommandId, DPLAYX_HresultToString( lpcErrorMsg->errorCode) );
454 DebugBreak();
455}
456
Note: See TracBrowser for help on using the repository browser.