From: Anton Baskanov baskanov@gmail.com
--- dlls/dplayx/dplay.c | 58 ++++++++++++--- dlls/dplayx/dplay_global.h | 2 + dlls/dplayx/dplayx_messages.c | 128 ++++++++++++++++++++++++++++++++++ dlls/dplayx/dplayx_messages.h | 22 ++++++ dlls/dplayx/tests/dplayx.c | 4 +- 5 files changed, 202 insertions(+), 12 deletions(-)
diff --git a/dlls/dplayx/dplay.c b/dlls/dplayx/dplay.c index 95e7a46d6a3..b670935771a 100644 --- a/dlls/dplayx/dplay.c +++ b/dlls/dplayx/dplay.c @@ -398,6 +398,46 @@ HRESULT DP_HandleMessage( IDirectPlayImpl *This, void *messageBody, DP_MSG_ToSelf( This, 1 ); /* This is a hack right now */ break;
+ case DPMSGCMD_ADDFORWARD: { + DPSP_MSG_ADDFORWARD *msg; + DPPLAYERINFO playerInfo; + DWORD offset = 0; + HRESULT hr; + + if( dwMessageBodySize < sizeof( DPSP_MSG_ADDFORWARD ) ) + return DPERR_GENERIC; + msg = (DPSP_MSG_ADDFORWARD *) messageBody; + offset += sizeof( DPSP_MSG_ADDFORWARD ); + + hr = DP_MSG_ReadPackedPlayer( (char *) messageBody, &offset, dwMessageBodySize, &playerInfo ); + if ( FAILED( hr ) ) + return hr; + + EnterCriticalSection( &This->lock ); + + if ( !This->dp2->bConnectionOpen ) + { + LeaveCriticalSection( &This->lock ); + return DP_OK; + } + + hr = DP_CreatePlayer( This, messageHeader, &msg->playerId, &playerInfo.name, + playerInfo.playerData, playerInfo.playerDataLength, playerInfo.spData, + playerInfo.spDataLength, playerInfo.flags & ~DPLAYI_PLAYER_PLAYERLOCAL, + NULL, FALSE ); + if ( FAILED( hr ) ) + { + LeaveCriticalSection( &This->lock ); + return hr; + } + + LeaveCriticalSection( &This->lock ); + + DP_MSG_SendAddForwardAck( This, msg->playerId ); + + break; + } + default: FIXME( "Unknown wCommandId %u. Ignoring message\n", wCommandId ); break; @@ -3470,7 +3510,6 @@ static HRESULT DP_SecureOpen( IDirectPlayImpl *This, const DPSESSIONDESC2 *lpsd, if( dwFlags & DPOPEN_JOIN ) { DWORD createFlags = DPLAYI_PLAYER_SYSPLAYER | DPLAYI_PLAYER_PLAYERLOCAL; - DPID dpidServerId = DPID_UNKNOWN; WCHAR *password;
password = DP_DuplicateString( lpsd->lpszPassword, FALSE, bAnsi ); @@ -3494,7 +3533,7 @@ static HRESULT DP_SecureOpen( IDirectPlayImpl *This, const DPSESSIONDESC2 *lpsd, * up. DPlay would then trigger the hEvent for the player the * message is directed to. */ - hr = DP_MSG_SendRequestPlayerId( This, createFlags, &dpidServerId ); + hr = DP_MSG_SendRequestPlayerId( This, createFlags, &This->dp2->systemPlayerId ); if( FAILED( hr ) ) { ERR( "Request for ID failed: %s\n", DPLAYX_HresultToString( hr ) ); @@ -3512,8 +3551,8 @@ static HRESULT DP_SecureOpen( IDirectPlayImpl *This, const DPSESSIONDESC2 *lpsd, /* No need to enter the critical section here as the messaging thread won't access the data * while bConnectionOpen is FALSE. */
- hr = DP_CreatePlayer( This, NULL, &dpidServerId, NULL, NULL, 0, NULL, 0, createFlags, NULL, - bAnsi ); + hr = DP_CreatePlayer( This, NULL, &This->dp2->systemPlayerId, NULL, NULL, 0, NULL, 0, + createFlags, NULL, bAnsi ); if( FAILED( hr ) ) { free( password ); @@ -3527,11 +3566,11 @@ static HRESULT DP_SecureOpen( IDirectPlayImpl *This, const DPSESSIONDESC2 *lpsd, return hr; }
- hr = DP_MSG_ForwardPlayerCreation( This, dpidServerId, password ); + hr = DP_MSG_ForwardPlayerCreation( This, This->dp2->systemPlayerId, password ); free( password ); if( FAILED( hr ) ) { - DP_DeletePlayer( This, dpidServerId ); + DP_DeletePlayer( This, This->dp2->systemPlayerId ); DP_IF_DestroyGroup( This, NULL, DPID_SYSTEM_GROUP, TRUE ); if( This->dp2->spData.lpCB->CloseEx ) { @@ -3545,10 +3584,11 @@ static HRESULT DP_SecureOpen( IDirectPlayImpl *This, const DPSESSIONDESC2 *lpsd, else if( dwFlags & DPOPEN_CREATE ) { DWORD createFlags = DPLAYI_PLAYER_APPSERVER | DPLAYI_PLAYER_PLAYERLOCAL; - DPID dpidNameServerId = DP_NextObjectId();
- hr = DP_CreatePlayer( This, NULL, &dpidNameServerId, NULL, NULL, 0, NULL, 0, createFlags, NULL, - bAnsi ); + This->dp2->systemPlayerId = DP_NextObjectId(); + + hr = DP_CreatePlayer( This, NULL, &This->dp2->systemPlayerId, NULL, NULL, 0, NULL, 0, + createFlags, NULL, bAnsi ); if( FAILED( hr ) ) { DP_IF_DestroyGroup( This, NULL, DPID_SYSTEM_GROUP, TRUE ); diff --git a/dlls/dplayx/dplay_global.h b/dlls/dplayx/dplay_global.h index bf70f6b096c..360114320fd 100644 --- a/dlls/dplayx/dplay_global.h +++ b/dlls/dplayx/dplay_global.h @@ -158,6 +158,8 @@ typedef struct tagDirectPlay2Data
lpGroupData lpSysGroup; /* System group with _everything_ in it */
+ DPID systemPlayerId; + LPDPSESSIONDESC2 lpSessionDesc;
/* I/O Msg queues */ diff --git a/dlls/dplayx/dplayx_messages.c b/dlls/dplayx/dplayx_messages.c index 90091d0aa03..26f2dc4e8e9 100644 --- a/dlls/dplayx/dplayx_messages.c +++ b/dlls/dplayx/dplayx_messages.c @@ -22,6 +22,7 @@
#include <stdarg.h> #include <string.h> +#include <limits.h> #include "windef.h" #include "winbase.h" #include "wingdi.h" @@ -321,6 +322,24 @@ static HRESULT DP_MSG_ReadString( char *data, DWORD *inoutOffset, DWORD maxSize, return DP_OK; }
+static HRESULT DP_MSG_ReadSizedString( char *data, DWORD *inoutOffset, DWORD maxSize, DWORD size, + WCHAR **string ) +{ + DWORD length = size / sizeof( WCHAR ) - 1; + DWORD offset = *inoutOffset; + + if( maxSize - offset < size ) + return DPERR_GENERIC; + + if ( ((WCHAR *) &data[ offset ])[ length ] != L'\0' ) + return DPERR_GENERIC; + + *string = (WCHAR *) &data[ offset ]; + *inoutOffset = offset + size; + + return DP_OK; +} + static HRESULT DP_MSG_ReadInteger( char *data, DWORD *inoutOffset, DWORD maxSize, DWORD size, DWORD *value ) { @@ -354,6 +373,75 @@ static HRESULT DP_MSG_ReadInteger( char *data, DWORD *inoutOffset, DWORD maxSize return DP_OK; }
+HRESULT DP_MSG_ReadPackedPlayer( char *data, DWORD *inoutOffset, DWORD maxSize, + DPPLAYERINFO *playerInfo ) +{ + DPLAYI_PACKEDPLAYER *packedPlayer; + DWORD offset = *inoutOffset; + HRESULT hr; + + memset( playerInfo, 0, sizeof( DPPLAYERINFO ) ); + + if( maxSize - offset < sizeof( DPLAYI_PACKEDPLAYER ) ) + return DPERR_GENERIC; + packedPlayer = (DPLAYI_PACKEDPLAYER *) &data[ offset ]; + offset += sizeof( DPLAYI_PACKEDPLAYER ); + + playerInfo->flags = packedPlayer->flags; + playerInfo->id = packedPlayer->id; + playerInfo->versionOrSystemPlayerId = packedPlayer->version; + playerInfo->playerDataLength = packedPlayer->playerDataLength; + playerInfo->spDataLength = packedPlayer->spDataLength; + playerInfo->playerCount = packedPlayer->playerCount; + playerInfo->parentId = packedPlayer->parentId; + + if( packedPlayer->shortNameLength ) + { + hr = DP_MSG_ReadSizedString( data, &offset, maxSize, packedPlayer->shortNameLength, + &playerInfo->name.lpszShortName ); + if( FAILED( hr ) ) + return hr; + } + + if( packedPlayer->longNameLength ) + { + hr = DP_MSG_ReadSizedString( data, &offset, maxSize, packedPlayer->longNameLength, + &playerInfo->name.lpszLongName ); + if( FAILED( hr ) ) + return hr; + } + + if( playerInfo->spDataLength ) + { + if( maxSize - offset < playerInfo->spDataLength ) + return DPERR_GENERIC; + playerInfo->spData = &data[ offset ]; + offset += playerInfo->spDataLength; + } + + if( playerInfo->playerDataLength ) + { + if( maxSize - offset < playerInfo->playerDataLength ) + return DPERR_GENERIC; + playerInfo->playerData = &data[ offset ]; + offset += playerInfo->playerDataLength; + } + + if( playerInfo->playerCount ) + { + if( UINT_MAX / sizeof( DPID ) < playerInfo->playerCount ) + return DPERR_GENERIC; + if( maxSize - offset < playerInfo->playerCount * sizeof( DPID ) ) + return DPERR_GENERIC; + playerInfo->playerIds = (DPID *) &data[ offset ]; + offset += playerInfo->playerCount * sizeof( DPID ); + } + + *inoutOffset = offset; + + return S_OK; +} + static HRESULT DP_MSG_ReadSuperPackedPlayer( char *data, DWORD *inoutOffset, DWORD maxSize, DPPLAYERINFO *playerInfo ) { @@ -615,6 +703,46 @@ HRESULT DP_MSG_ForwardPlayerCreation( IDirectPlayImpl *This, DPID dpidServer, WC return hr; }
+HRESULT DP_MSG_SendAddForwardAck( IDirectPlayImpl *This, DPID id ) +{ + SGBUFFER buffers[ 2 ] = { 0 }; + DPSP_MSG_ADDFORWARDACK msg; + DPSP_SENDEXDATA sendData; + HRESULT hr; + + msg.envelope.dwMagic = DPMSGMAGIC_DPLAYMSG; + msg.envelope.wCommandId = DPMSGCMD_ADDFORWARDACK; + msg.envelope.wVersion = DPMSGVER_DP6; + msg.id = id; + + buffers[ 0 ].len = This->dp2->spData.dwSPHeaderSize; + buffers[ 0 ].pData = NULL; + buffers[ 1 ].len = sizeof( msg ); + buffers[ 1 ].pData = (UCHAR *)&msg; + + sendData.lpISP = This->dp2->spData.lpISP; + sendData.dwFlags = DPSEND_GUARANTEED; + sendData.idPlayerTo = 0; + sendData.idPlayerFrom = This->dp2->systemPlayerId; + sendData.lpSendBuffers = buffers; + sendData.cBuffers = ARRAYSIZE( buffers ); + sendData.dwMessageSize = DP_MSG_ComputeMessageSize( sendData.lpSendBuffers, sendData.cBuffers ); + sendData.dwPriority = 0; + sendData.dwTimeout = 0; + sendData.lpDPContext = NULL; + sendData.lpdwSPMsgID = NULL; + sendData.bSystemMessage = TRUE; + + hr = (*This->dp2->spData.lpCB->SendEx)( &sendData ); + if( FAILED( hr ) ) + { + ERR( "Send failed: %s\n", DPLAYX_HresultToString( hr ) ); + return hr; + } + + return DP_OK; +} + /* Queue up a structure indicating that we want a reply of type wReplyCommandId. DPlay does * not seem to offer any way of uniquely differentiating between replies of the same type * relative to the request sent. There is an implicit assumption that there will be no diff --git a/dlls/dplayx/dplayx_messages.h b/dlls/dplayx/dplayx_messages.h index e8453200d26..1ce1fc5ba09 100644 --- a/dlls/dplayx/dplayx_messages.h +++ b/dlls/dplayx/dplayx_messages.h @@ -50,7 +50,10 @@ DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart,
HRESULT DP_MSG_SendRequestPlayerId( IDirectPlayImpl *This, DWORD dwFlags, LPDPID lpdipidAllocatedId ); +HRESULT DP_MSG_ReadPackedPlayer( char *data, DWORD *offset, DWORD maxSize, + DPPLAYERINFO *playerInfo ); HRESULT DP_MSG_ForwardPlayerCreation( IDirectPlayImpl *This, DPID dpidServer, WCHAR *password ); +HRESULT DP_MSG_SendAddForwardAck( IDirectPlayImpl *This, DPID id );
void DP_MSG_ReplyReceived( IDirectPlayImpl *This, WORD wCommandId, LPCVOID lpMsgBody, DWORD dwMsgBodySize, @@ -106,6 +109,9 @@ typedef struct
#define DPMSGCMD_SUPERENUMPLAYERSREPLY 41
+#define DPMSGCMD_ADDFORWARD 46 +#define DPMSGCMD_ADDFORWARDACK 47 + #define DPMSGCMD_JUSTENVELOPE 1000 #define DPMSGCMD_JUSTENVELOPEREPLY 1001
@@ -271,6 +277,22 @@ typedef struct DWORD passwordOffset; } DPSP_MSG_SUPERENUMPLAYERSREPLY;
+typedef struct +{ + DPMSG_SENDENVELOPE envelope; + DPID toId; + DPID playerId; + DPID groupId; + DWORD createOffset; + DWORD passwordOffset; +} DPSP_MSG_ADDFORWARD; + +typedef struct +{ + DPMSG_SENDENVELOPE envelope; + DPID id; +} DPSP_MSG_ADDFORWARDACK; + #include "poppack.h"
#endif diff --git a/dlls/dplayx/tests/dplayx.c b/dlls/dplayx/tests/dplayx.c index 5936dd744d9..7249704f484 100644 --- a/dlls/dplayx/tests/dplayx.c +++ b/dlls/dplayx/tests/dplayx.c @@ -1553,9 +1553,7 @@ static unsigned short receiveAddForwardAck_( int line, SOCKET sock, DPID expecte int wsResult;
wsResult = receiveMessage_( line, sock, &request, sizeof( request ) ); - todo_wine ok_( __FILE__, line )( wsResult == sizeof( request ), "recv() returned %d.\n", wsResult ); - if ( wsResult == SOCKET_ERROR ) - return 0; + ok_( __FILE__, line )( wsResult == sizeof( request ), "recv() returned %d.\n", wsResult );
port = checkSpHeader_( line, &request.spHeader, sizeof( request ), FALSE ); checkMessageHeader_( line, &request.request.header, 47 );