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