1 /* DirectPlay & DirectPlayLobby messaging implementation
3 * Copyright 2000 - Peter Hunnisett
5 * <presently under construction - contact hunnise@nortelnetworks.com>
10 #include "debugtools.h"
16 #include "dplayx_messages.h"
17 #include "dplay_global.h"
18 #include "dplayx_global.h"
20 DEFAULT_DEBUG_CHANNEL(dplay)
22 typedef struct tagMSGTHREADINFO
28 } MSGTHREADINFO, *LPMSGTHREADINFO;
31 static DWORD CALLBACK DPL_MSG_ThreadMain( LPVOID lpContext );
33 /* Create the message reception thread to allow the application to receive
34 * asynchronous message reception
36 DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart,
37 HANDLE hDeath, HANDLE hConnRead )
40 LPMSGTHREADINFO lpThreadInfo;
42 lpThreadInfo = HeapAlloc( GetProcessHeap(), 0, sizeof( *lpThreadInfo ) );
43 if( lpThreadInfo == NULL )
48 /* The notify event may or may not exist. Depends if async comm or not */
50 !DuplicateHandle( GetCurrentProcess(), hNotifyEvent,
51 GetCurrentProcess(), &lpThreadInfo->hNotifyEvent,
52 0, FALSE, DUPLICATE_SAME_ACCESS ) )
54 ERR( "Unable to duplicate event handle\n" );
58 /* These 3 handles don't need to be duplicated because we don't keep a
59 * reference to them where they're created. They're created specifically
60 * for the message thread
62 lpThreadInfo->hStart = hStart;
63 lpThreadInfo->hDeath = hDeath;
64 lpThreadInfo->hSettingRead = hConnRead;
66 if( !CreateThread( NULL, /* Security attribs */
68 DPL_MSG_ThreadMain, /* Msg reception function */
69 lpThreadInfo, /* Msg reception func parameter */
71 &dwMsgThreadId /* Updated with thread id */
75 ERR( "Unable to create msg thread\n" );
79 /* FIXME: Should I be closing the handle to the thread or does that
80 terminate the thread? */
86 HeapFree( GetProcessHeap(), 0, lpThreadInfo );
91 static DWORD CALLBACK DPL_MSG_ThreadMain( LPVOID lpContext )
93 LPMSGTHREADINFO lpThreadInfo = (LPMSGTHREADINFO)lpContext;
96 TRACE( "Msg thread created. Waiting on app startup\n" );
98 /* Wait to ensure that the lobby application is started w/ 1 min timeout */
99 dwWaitResult = WaitForSingleObject( lpThreadInfo->hStart, 10000 /* 10 sec */ );
100 if( dwWaitResult == WAIT_TIMEOUT )
102 FIXME( "Should signal app/wait creation failure (0x%08lx)\n", dwWaitResult );
106 /* Close this handle as it's not needed anymore */
107 CloseHandle( lpThreadInfo->hStart );
108 lpThreadInfo->hStart = 0;
110 /* Wait until the lobby knows what it is */
111 dwWaitResult = WaitForSingleObject( lpThreadInfo->hSettingRead, INFINITE );
112 if( dwWaitResult == WAIT_TIMEOUT )
114 ERR( "App Read connection setting timeout fail (0x%08lx)\n", dwWaitResult );
117 /* Close this handle as it's not needed anymore */
118 CloseHandle( lpThreadInfo->hSettingRead );
119 lpThreadInfo->hSettingRead = 0;
121 TRACE( "App created && intialized starting main message reception loop\n" );
127 HANDLE hNullHandle = NULL;
129 HANDLE hNullHandle = 0;
132 GetMessageW( &lobbyMsg, hNullHandle, 0, 0 );
136 TRACE( "Msg thread exiting!\n" );
137 HeapFree( GetProcessHeap(), 0, lpThreadInfo );
143 HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags,
144 LPDPID lpdpidAllocatedId )
147 LPDPMSG_REQUESTNEWPLAYERID lpMsgBody;
152 dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody );
154 lpMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwMsgSize );
156 lpMsgBody = (LPDPMSG_REQUESTNEWPLAYERID)( (BYTE*)lpMsg +
157 This->dp2->spData.dwSPHeaderSize );
159 lpMsgBody->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
160 lpMsgBody->envelope.wCommandId = DPMSGCMD_REQUESTNEWPLAYERID;
161 lpMsgBody->envelope.wVersion = DPMSGVER_DP6;
163 lpMsgBody->dwFlags = dwFlags;
165 /* FIXME: Need to have a more advanced queuing system as this needs to
166 * block on send until we get response. Otherwise we need to be
167 * able to ensure we can pick out the exact response. Of course,
168 * with something as non critical as this, would it matter? The
169 * id has been effectively reserved for this session...
174 data.dwFlags = DPSEND_GUARANTEED;
175 data.idPlayerTo = 0; /* Name server */
176 data.idPlayerFrom = 0; /* Sending from DP */
177 data.lpMessage = lpMsg;
178 data.dwMessageSize = dwMsgSize;
179 data.bSystemMessage = TRUE; /* Allow reply to be sent */
180 data.lpISP = This->dp2->spData.lpISP;
182 /* Setup for receipt */
183 This->dp2->hMsgReceipt = CreateEventA( NULL, FALSE, FALSE, NULL );
185 TRACE( "Sending request for player id\n" );
187 hr = (*This->dp2->spData.lpCB->Send)( &data );
191 ERR( "Request for new playerID send failed: %s\n",
192 DPLAYX_HresultToString( hr ) );
193 return DPERR_NOCONNECTION;
197 dwWaitReturn = WaitForSingleObject( This->dp2->hMsgReceipt, 30000 );
198 if( dwWaitReturn != WAIT_OBJECT_0 )
200 ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
204 CloseHandle( This->dp2->hMsgReceipt );
205 This->dp2->hMsgReceipt = 0;
207 /* Need to examine the data and extract the new player id */
210 LPCDPMSG_NEWPLAYERIDREPLY lpcReply;
212 lpcReply = (LPCDPMSG_NEWPLAYERIDREPLY)This->dp2->lpMsgReceived;
214 *lpdpidAllocatedId = lpcReply->dpidNewPlayerId;
216 TRACE( "Received reply for id = 0x%08lx\n", lpcReply->dpidNewPlayerId );
218 /* FIXME: I think that the rest of the message has something to do
219 * with remote data for the player that perhaps I need to setup.
222 /* Set the passed service provider data */
223 IDirectPlaySP_SetSPData( This->dp2->spData.lpISP, data,
224 msgsize, DPSET_REMOTE );
228 HeapFree( GetProcessHeap(), 0, This->dp2->lpMsgReceived );
229 This->dp2->lpMsgReceived = NULL;
236 /* This function seems to cause a trap in the SP. It would seem unnecessary */
237 /* FIXME: Remove this method if not required */
238 HRESULT DP_MSG_OpenStream( IDirectPlay2AImpl* This )
243 data.dwFlags = DPSEND_OPENSTREAM;
244 data.idPlayerTo = 0; /* Name server */
245 data.idPlayerFrom = 0; /* From DP itself */
246 data.lpMessage = NULL;
247 data.dwMessageSize = This->dp2->spData.dwSPHeaderSize;
248 data.bSystemMessage = FALSE; /* FIXME? */
249 data.lpISP = This->dp2->spData.lpISP;
251 hr = (*This->dp2->spData.lpCB->Send)( &data );
255 ERR( "Request for open stream send failed: %s\n",
256 DPLAYX_HresultToString( hr ) );
259 /* FIXME: hack to give some time for channel to open */
260 SleepEx( 1000 /* 1 sec */, FALSE );