Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygendplayx_messages.c
Go to the documentation of this file.
00001 /* DirectPlay & DirectPlayLobby messaging implementation 00002 * 00003 * Copyright 2000,2001 - Peter Hunnisett 00004 * 00005 * This library is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU Lesser General Public 00007 * License as published by the Free Software Foundation; either 00008 * version 2.1 of the License, or (at your option) any later version. 00009 * 00010 * This library is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 * Lesser General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Lesser General Public 00016 * License along with this library; if not, write to the Free Software 00017 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00018 * 00019 * NOTES 00020 * o Messaging interface required for both DirectPlay and DirectPlayLobby. 00021 */ 00022 00023 #include <stdarg.h> 00024 #include <string.h> 00025 #include "windef.h" 00026 #include "winbase.h" 00027 #include "wingdi.h" 00028 #include "winuser.h" 00029 #include "winerror.h" 00030 00031 #include "dplayx_messages.h" 00032 #include "dplay_global.h" 00033 #include "dplayx_global.h" 00034 #include "name_server.h" 00035 #include "wine/debug.h" 00036 00037 WINE_DEFAULT_DEBUG_CHANNEL(dplay); 00038 00039 typedef struct tagMSGTHREADINFO 00040 { 00041 HANDLE hStart; 00042 HANDLE hDeath; 00043 HANDLE hSettingRead; 00044 HANDLE hNotifyEvent; 00045 } MSGTHREADINFO, *LPMSGTHREADINFO; 00046 00047 static DWORD CALLBACK DPL_MSG_ThreadMain( LPVOID lpContext ); 00048 static LPVOID DP_MSG_ExpectReply( IDirectPlay2AImpl* This, LPDPSP_SENDDATA data, 00049 DWORD dwWaitTime, WORD wReplyCommandId, 00050 LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize ); 00051 00052 00053 /* Create the message reception thread to allow the application to receive 00054 * asynchronous message reception 00055 */ 00056 DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart, 00057 HANDLE hDeath, HANDLE hConnRead ) 00058 { 00059 DWORD dwMsgThreadId; 00060 LPMSGTHREADINFO lpThreadInfo; 00061 HANDLE hThread; 00062 00063 lpThreadInfo = HeapAlloc( GetProcessHeap(), 0, sizeof( *lpThreadInfo ) ); 00064 if( lpThreadInfo == NULL ) 00065 { 00066 return 0; 00067 } 00068 00069 /* The notify event may or may not exist. Depends if async comm or not */ 00070 if( hNotifyEvent && 00071 !DuplicateHandle( GetCurrentProcess(), hNotifyEvent, 00072 GetCurrentProcess(), &lpThreadInfo->hNotifyEvent, 00073 0, FALSE, DUPLICATE_SAME_ACCESS ) ) 00074 { 00075 ERR( "Unable to duplicate event handle\n" ); 00076 goto error; 00077 } 00078 00079 /* These 3 handles don't need to be duplicated because we don't keep a 00080 * reference to them where they're created. They're created specifically 00081 * for the message thread 00082 */ 00083 lpThreadInfo->hStart = hStart; 00084 lpThreadInfo->hDeath = hDeath; 00085 lpThreadInfo->hSettingRead = hConnRead; 00086 00087 hThread = CreateThread( NULL, /* Security attribs */ 00088 0, /* Stack */ 00089 DPL_MSG_ThreadMain, /* Msg reception function */ 00090 lpThreadInfo, /* Msg reception func parameter */ 00091 0, /* Flags */ 00092 &dwMsgThreadId /* Updated with thread id */ 00093 ); 00094 if ( hThread == NULL ) 00095 { 00096 ERR( "Unable to create msg thread\n" ); 00097 goto error; 00098 } 00099 00100 CloseHandle(hThread); 00101 00102 return dwMsgThreadId; 00103 00104 error: 00105 00106 HeapFree( GetProcessHeap(), 0, lpThreadInfo ); 00107 00108 return 0; 00109 } 00110 00111 static DWORD CALLBACK DPL_MSG_ThreadMain( LPVOID lpContext ) 00112 { 00113 LPMSGTHREADINFO lpThreadInfo = (LPMSGTHREADINFO)lpContext; 00114 DWORD dwWaitResult; 00115 00116 TRACE( "Msg thread created. Waiting on app startup\n" ); 00117 00118 /* Wait to ensure that the lobby application is started w/ 1 min timeout */ 00119 dwWaitResult = WaitForSingleObject( lpThreadInfo->hStart, 10000 /* 10 sec */ ); 00120 if( dwWaitResult == WAIT_TIMEOUT ) 00121 { 00122 FIXME( "Should signal app/wait creation failure (0x%08lx)\n", dwWaitResult ); 00123 goto end_of_thread; 00124 } 00125 00126 /* Close this handle as it's not needed anymore */ 00127 CloseHandle( lpThreadInfo->hStart ); 00128 lpThreadInfo->hStart = 0; 00129 00130 /* Wait until the lobby knows what it is */ 00131 dwWaitResult = WaitForSingleObject( lpThreadInfo->hSettingRead, INFINITE ); 00132 if( dwWaitResult == WAIT_TIMEOUT ) 00133 { 00134 ERR( "App Read connection setting timeout fail (0x%08lx)\n", dwWaitResult ); 00135 } 00136 00137 /* Close this handle as it's not needed anymore */ 00138 CloseHandle( lpThreadInfo->hSettingRead ); 00139 lpThreadInfo->hSettingRead = 0; 00140 00141 TRACE( "App created && intialized starting main message reception loop\n" ); 00142 00143 for ( ;; ) 00144 { 00145 MSG lobbyMsg; 00146 GetMessageW( &lobbyMsg, 0, 0, 0 ); 00147 } 00148 00149 end_of_thread: 00150 TRACE( "Msg thread exiting!\n" ); 00151 HeapFree( GetProcessHeap(), 0, lpThreadInfo ); 00152 00153 return 0; 00154 } 00155 00156 /* DP messageing stuff */ 00157 static HANDLE DP_MSG_BuildAndLinkReplyStruct( IDirectPlay2Impl* This, 00158 LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList, 00159 WORD wReplyCommandId ); 00160 static LPVOID DP_MSG_CleanReplyStruct( LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList, 00161 LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize ); 00162 00163 00164 static 00165 HANDLE DP_MSG_BuildAndLinkReplyStruct( IDirectPlay2Impl* This, 00166 LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList, WORD wReplyCommandId ) 00167 { 00168 lpReplyStructList->replyExpected.hReceipt = CreateEventW( NULL, FALSE, FALSE, NULL ); 00169 lpReplyStructList->replyExpected.wExpectedReply = wReplyCommandId; 00170 lpReplyStructList->replyExpected.lpReplyMsg = NULL; 00171 lpReplyStructList->replyExpected.dwMsgBodySize = 0; 00172 00173 /* Insert into the message queue while locked */ 00174 EnterCriticalSection( &This->unk->DP_lock ); 00175 DPQ_INSERT( This->dp2->replysExpected, lpReplyStructList, replysExpected ); 00176 LeaveCriticalSection( &This->unk->DP_lock ); 00177 00178 return lpReplyStructList->replyExpected.hReceipt; 00179 } 00180 00181 static 00182 LPVOID DP_MSG_CleanReplyStruct( LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList, 00183 LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize ) 00184 { 00185 CloseHandle( lpReplyStructList->replyExpected.hReceipt ); 00186 00187 *lplpReplyMsg = lpReplyStructList->replyExpected.lpReplyMsg; 00188 *lpdwMsgBodySize = lpReplyStructList->replyExpected.dwMsgBodySize; 00189 00190 return lpReplyStructList->replyExpected.lpReplyMsg; 00191 } 00192 00193 HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags, 00194 LPDPID lpdpidAllocatedId ) 00195 { 00196 LPVOID lpMsg; 00197 LPDPMSG_REQUESTNEWPLAYERID lpMsgBody; 00198 DWORD dwMsgSize; 00199 HRESULT hr = DP_OK; 00200 00201 dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody ); 00202 00203 lpMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwMsgSize ); 00204 00205 lpMsgBody = (LPDPMSG_REQUESTNEWPLAYERID)( (BYTE*)lpMsg + 00206 This->dp2->spData.dwSPHeaderSize ); 00207 00208 /* Compose dplay message envelope */ 00209 lpMsgBody->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG; 00210 lpMsgBody->envelope.wCommandId = DPMSGCMD_REQUESTNEWPLAYERID; 00211 lpMsgBody->envelope.wVersion = DPMSGVER_DP6; 00212 00213 /* Compose the body of the message */ 00214 lpMsgBody->dwFlags = dwFlags; 00215 00216 /* Send the message */ 00217 { 00218 DPSP_SENDDATA data; 00219 00220 data.dwFlags = DPSEND_GUARANTEED; 00221 data.idPlayerTo = 0; /* Name server */ 00222 data.idPlayerFrom = 0; /* Sending from DP */ 00223 data.lpMessage = lpMsg; 00224 data.dwMessageSize = dwMsgSize; 00225 data.bSystemMessage = TRUE; /* Allow reply to be sent */ 00226 data.lpISP = This->dp2->spData.lpISP; 00227 00228 TRACE( "Asking for player id w/ dwFlags 0x%08lx\n", 00229 lpMsgBody->dwFlags ); 00230 00231 DP_MSG_ExpectReply( This, &data, DPMSG_DEFAULT_WAIT_TIME, DPMSGCMD_NEWPLAYERIDREPLY, 00232 &lpMsg, &dwMsgSize ); 00233 } 00234 00235 /* Need to examine the data and extract the new player id */ 00236 if( !FAILED(hr) ) 00237 { 00238 LPCDPMSG_NEWPLAYERIDREPLY lpcReply; 00239 00240 lpcReply = (LPCDPMSG_NEWPLAYERIDREPLY)lpMsg; 00241 00242 *lpdpidAllocatedId = lpcReply->dpidNewPlayerId; 00243 00244 TRACE( "Received reply for id = 0x%08lx\n", lpcReply->dpidNewPlayerId ); 00245 00246 /* FIXME: I think that the rest of the message has something to do 00247 * with remote data for the player that perhaps I need to setup. 00248 * However, with the information that is passed, all that it could 00249 * be used for is a standardized intialization value, which I'm 00250 * guessing we can do without. Unless the message content is the same 00251 * for several different messages? 00252 */ 00253 00254 HeapFree( GetProcessHeap(), 0, lpMsg ); 00255 } 00256 00257 return hr; 00258 } 00259 00260 HRESULT DP_MSG_ForwardPlayerCreation( IDirectPlay2AImpl* This, DPID dpidServer ) 00261 { 00262 LPVOID lpMsg; 00263 LPDPMSG_FORWARDADDPLAYER lpMsgBody; 00264 DWORD dwMsgSize; 00265 HRESULT hr = DP_OK; 00266 00267 dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody ); 00268 00269 lpMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwMsgSize ); 00270 00271 lpMsgBody = (LPDPMSG_FORWARDADDPLAYER)( (BYTE*)lpMsg + 00272 This->dp2->spData.dwSPHeaderSize ); 00273 00274 /* Compose dplay message envelope */ 00275 lpMsgBody->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG; 00276 lpMsgBody->envelope.wCommandId = DPMSGCMD_FORWARDADDPLAYER; 00277 lpMsgBody->envelope.wVersion = DPMSGVER_DP6; 00278 00279 #if 0 00280 { 00281 LPBYTE lpPData; 00282 DWORD dwDataSize; 00283 00284 /* SP Player remote data needs to be propagated at some point - is this the point? */ 00285 IDirectPlaySP_GetSPPlayerData( This->dp2->spData.lpISP, 0, (LPVOID*)&lpPData, &dwDataSize, DPSET_REMOTE ); 00286 00287 ERR( "Player Data size is 0x%08lx\n" 00288 "[%02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x]\n" 00289 "[%02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x]\n", 00290 00291 dwDataSize, 00292 lpPData[0], lpPData[1], lpPData[2], lpPData[3], lpPData[4], 00293 lpPData[5], lpPData[6], lpPData[7], lpPData[8], lpPData[9], 00294 lpPData[10], lpPData[11], lpPData[12], lpPData[13], lpPData[14], 00295 lpPData[15], lpPData[16], lpPData[17], lpPData[18], lpPData[19], 00296 lpPData[20], lpPData[21], lpPData[22], lpPData[23], lpPData[24], 00297 lpPData[25], lpPData[26], lpPData[27], lpPData[28], lpPData[29], 00298 lpPData[30], lpPData[31] 00299 ); 00300 DebugBreak(); 00301 } 00302 #endif 00303 00304 /* Compose body of message */ 00305 lpMsgBody->dpidAppServer = dpidServer; 00306 lpMsgBody->unknown2[0] = 0x0; 00307 lpMsgBody->unknown2[1] = 0x1c; 00308 lpMsgBody->unknown2[2] = 0x6c; 00309 lpMsgBody->unknown2[3] = 0x50; 00310 lpMsgBody->unknown2[4] = 0x9; 00311 00312 lpMsgBody->dpidAppServer2 = dpidServer; 00313 lpMsgBody->unknown3[0] = 0x0; 00314 lpMsgBody->unknown3[0] = 0x0; 00315 lpMsgBody->unknown3[0] = 0x20; 00316 lpMsgBody->unknown3[0] = 0x0; 00317 lpMsgBody->unknown3[0] = 0x0; 00318 00319 lpMsgBody->dpidAppServer3 = dpidServer; 00320 lpMsgBody->unknown4[0] = 0x30; 00321 lpMsgBody->unknown4[1] = 0xb; 00322 lpMsgBody->unknown4[2] = 0x0; 00323 00324 lpMsgBody->unknown4[3] = NS_GetNsMagic( This->dp2->lpNameServerData ) - 00325 0x02000000; 00326 TRACE( "Setting first magic to 0x%08lx\n", lpMsgBody->unknown4[3] ); 00327 00328 lpMsgBody->unknown4[4] = 0x0; 00329 lpMsgBody->unknown4[5] = 0x0; 00330 lpMsgBody->unknown4[6] = 0x0; 00331 00332 #if 0 00333 lpMsgBody->unknown4[7] = NS_GetOtherMagic( This->dp2->lpNameServerData ) 00334 #else 00335 lpMsgBody->unknown4[7] = NS_GetNsMagic( This->dp2->lpNameServerData ); 00336 #endif 00337 TRACE( "Setting second magic to 0x%08lx\n", lpMsgBody->unknown4[7] ); 00338 00339 lpMsgBody->unknown4[8] = 0x0; 00340 lpMsgBody->unknown4[9] = 0x0; 00341 lpMsgBody->unknown4[10] = 0x0; 00342 lpMsgBody->unknown4[11] = 0x0; 00343 00344 lpMsgBody->unknown5[0] = 0x0; 00345 lpMsgBody->unknown5[1] = 0x0; 00346 00347 /* Send the message */ 00348 { 00349 DPSP_SENDDATA data; 00350 00351 data.dwFlags = DPSEND_GUARANTEED; 00352 data.idPlayerTo = 0; /* Name server */ 00353 data.idPlayerFrom = dpidServer; /* Sending from session server */ 00354 data.lpMessage = lpMsg; 00355 data.dwMessageSize = dwMsgSize; 00356 data.bSystemMessage = TRUE; /* Allow reply to be sent */ 00357 data.lpISP = This->dp2->spData.lpISP; 00358 00359 TRACE( "Sending forward player request with 0x%08lx\n", dpidServer ); 00360 00361 lpMsg = DP_MSG_ExpectReply( This, &data, 00362 DPMSG_WAIT_60_SECS, 00363 DPMSGCMD_GETNAMETABLEREPLY, 00364 &lpMsg, &dwMsgSize ); 00365 } 00366 00367 /* Need to examine the data and extract the new player id */ 00368 if( lpMsg != NULL ) 00369 { 00370 FIXME( "Name Table reply received: stub\n" ); 00371 } 00372 00373 return hr; 00374 } 00375 00376 /* Queue up a structure indicating that we want a reply of type wReplyCommandId. DPlay does 00377 * not seem to offer any way of uniquely differentiating between replies of the same type 00378 * relative to the request sent. There is an implicit assumption that there will be no 00379 * ordering issues on sends and receives from the opposite machine. No wonder MS is not 00380 * a networking company. 00381 */ 00382 static 00383 LPVOID DP_MSG_ExpectReply( IDirectPlay2AImpl* This, LPDPSP_SENDDATA lpData, 00384 DWORD dwWaitTime, WORD wReplyCommandId, 00385 LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize ) 00386 { 00387 HRESULT hr; 00388 HANDLE hMsgReceipt; 00389 DP_MSG_REPLY_STRUCT_LIST replyStructList; 00390 DWORD dwWaitReturn; 00391 00392 /* Setup for receipt */ 00393 hMsgReceipt = DP_MSG_BuildAndLinkReplyStruct( This, &replyStructList, 00394 wReplyCommandId ); 00395 00396 TRACE( "Sending msg and expecting cmd %u in reply within %lu ticks\n", 00397 wReplyCommandId, dwWaitTime ); 00398 hr = (*This->dp2->spData.lpCB->Send)( lpData ); 00399 00400 if( FAILED(hr) ) 00401 { 00402 ERR( "Send failed: %s\n", DPLAYX_HresultToString( hr ) ); 00403 return NULL; 00404 } 00405 00406 /* The reply message will trigger the hMsgReceipt event effectively switching 00407 * control back to this thread. See DP_MSG_ReplyReceived. 00408 */ 00409 dwWaitReturn = WaitForSingleObject( hMsgReceipt, dwWaitTime ); 00410 if( dwWaitReturn != WAIT_OBJECT_0 ) 00411 { 00412 ERR( "Wait failed 0x%08lx\n", dwWaitReturn ); 00413 return NULL; 00414 } 00415 00416 /* Clean Up */ 00417 return DP_MSG_CleanReplyStruct( &replyStructList, lplpReplyMsg, lpdwMsgBodySize ); 00418 } 00419 00420 /* Determine if there is a matching request for this incoming message and then copy 00421 * all important data. It is quite silly to have to copy the message, but the documents 00422 * indicate that a copy is taken. Silly really. 00423 */ 00424 void DP_MSG_ReplyReceived( IDirectPlay2AImpl* This, WORD wCommandId, 00425 LPCVOID lpcMsgBody, DWORD dwMsgBodySize ) 00426 { 00427 LPDP_MSG_REPLY_STRUCT_LIST lpReplyList; 00428 00429 #if 0 00430 if( wCommandId == DPMSGCMD_FORWARDADDPLAYER ) 00431 { 00432 DebugBreak(); 00433 } 00434 #endif 00435 00436 /* Find, and immediately remove (to avoid double triggering), the appropriate entry. Call locked to 00437 * avoid problems. 00438 */ 00439 EnterCriticalSection( &This->unk->DP_lock ); 00440 DPQ_REMOVE_ENTRY( This->dp2->replysExpected, replysExpected, replyExpected.wExpectedReply,\ 00441 ==, wCommandId, lpReplyList ); 00442 LeaveCriticalSection( &This->unk->DP_lock ); 00443 00444 if( lpReplyList != NULL ) 00445 { 00446 lpReplyList->replyExpected.dwMsgBodySize = dwMsgBodySize; 00447 lpReplyList->replyExpected.lpReplyMsg = HeapAlloc( GetProcessHeap(), 00448 HEAP_ZERO_MEMORY, 00449 dwMsgBodySize ); 00450 CopyMemory( lpReplyList->replyExpected.lpReplyMsg, 00451 lpcMsgBody, dwMsgBodySize ); 00452 00453 /* Signal the thread which sent the message that it has a reply */ 00454 SetEvent( lpReplyList->replyExpected.hReceipt ); 00455 } 00456 else 00457 { 00458 ERR( "No receipt event set - only expecting in reply mode\n" ); 00459 DebugBreak(); 00460 } 00461 } 00462 00463 void DP_MSG_ToSelf( IDirectPlay2AImpl* This, DPID dpidSelf ) 00464 { 00465 LPVOID lpMsg; 00466 LPDPMSG_SENDENVELOPE lpMsgBody; 00467 DWORD dwMsgSize; 00468 00469 dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody ); 00470 00471 lpMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwMsgSize ); 00472 00473 lpMsgBody = (LPDPMSG_SENDENVELOPE)( (BYTE*)lpMsg + 00474 This->dp2->spData.dwSPHeaderSize ); 00475 00476 /* Compose dplay message envelope */ 00477 lpMsgBody->dwMagic = DPMSGMAGIC_DPLAYMSG; 00478 lpMsgBody->wCommandId = DPMSGCMD_JUSTENVELOPE; 00479 lpMsgBody->wVersion = DPMSGVER_DP6; 00480 00481 /* Send the message to ourselves */ 00482 { 00483 DPSP_SENDDATA data; 00484 00485 data.dwFlags = 0; 00486 data.idPlayerTo = dpidSelf; /* Sending to session server */ 00487 data.idPlayerFrom = 0; /* Sending from session server */ 00488 data.lpMessage = lpMsg; 00489 data.dwMessageSize = dwMsgSize; 00490 data.bSystemMessage = TRUE; /* Allow reply to be sent */ 00491 data.lpISP = This->dp2->spData.lpISP; 00492 00493 lpMsg = DP_MSG_ExpectReply( This, &data, 00494 DPMSG_WAIT_5_SECS, 00495 DPMSGCMD_JUSTENVELOPE, 00496 &lpMsg, &dwMsgSize ); 00497 } 00498 } 00499 00500 void DP_MSG_ErrorReceived( IDirectPlay2AImpl* This, WORD wCommandId, 00501 LPCVOID lpMsgBody, DWORD dwMsgBodySize ) 00502 { 00503 LPCDPMSG_FORWARDADDPLAYERNACK lpcErrorMsg; 00504 00505 lpcErrorMsg = (LPCDPMSG_FORWARDADDPLAYERNACK)lpMsgBody; 00506 00507 ERR( "Received error message %u. Error is %s\n", 00508 wCommandId, DPLAYX_HresultToString( lpcErrorMsg->errorCode) ); 00509 DebugBreak(); 00510 } Generated on Mon May 28 2012 04:21:07 for ReactOS by
1.7.6.1
|