-- v3: dpwsockx: Broadcast enumeration request in EnumSessions(). dpwsockx: Start listening for incoming TCP connections in EnumSessions().
From: Anton Baskanov baskanov@gmail.com
--- dlls/dplayx/tests/Makefile.in | 2 +- dlls/dplayx/tests/dplayx.c | 672 +++++++++++++++++++++++++++++++++- 2 files changed, 671 insertions(+), 3 deletions(-)
diff --git a/dlls/dplayx/tests/Makefile.in b/dlls/dplayx/tests/Makefile.in index 4b292a9806d..3587cda4d5a 100644 --- a/dlls/dplayx/tests/Makefile.in +++ b/dlls/dplayx/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = dplayx.dll -IMPORTS = ole32 oleaut32 version advapi32 +IMPORTS = ole32 oleaut32 version advapi32 ws2_32
SOURCES = \ dplayx.c diff --git a/dlls/dplayx/tests/dplayx.c b/dlls/dplayx/tests/dplayx.c index e7c2d0b5258..fcc4eb7de5f 100644 --- a/dlls/dplayx/tests/dplayx.c +++ b/dlls/dplayx/tests/dplayx.c @@ -24,6 +24,7 @@ #include <dplay.h> #include <dplobby.h> #include <netfw.h> +#include <winsock2.h>
static HRESULT (WINAPI *pDirectPlayEnumerateA)( LPDPENUMDPCALLBACKA, void* ); static HRESULT (WINAPI *pDirectPlayEnumerateW)( LPDPENUMDPCALLBACKW, void* ); @@ -655,6 +656,291 @@ static void check_messages( IDirectPlay4 *pDP, DPID *dpid, DWORD dpidSize, free( lpData ); }
+typedef struct +{ + IDirectPlay4 *dp; + DPSESSIONDESC2 *dpsd; + DWORD timeout; + LPDPENUMSESSIONSCALLBACK2 callback; + void *context; + DWORD flags; + + HRESULT hr; + + HANDLE thread; +} EnumSessionsParam; + +static CALLBACK DWORD enumSessionsProc( void *p ) +{ + EnumSessionsParam *param = p; + + param->hr = IDirectPlayX_EnumSessions( param->dp, param->dpsd, param->timeout, param->callback, + param->context, param->flags ); + + return 0; +} + +static HANDLE enumSessionsAsync( IDirectPlay4 *dp, DPSESSIONDESC2 *dpsd, DWORD timeout, + LPDPENUMSESSIONSCALLBACK2 callback, void *context, DWORD flags ) +{ + EnumSessionsParam *param; + + param = calloc( 1, sizeof( EnumSessionsParam ) ); + + param->dp = dp; + param->dpsd = dpsd; + param->timeout = timeout; + param->callback = callback; + param->context = context; + param->flags = flags; + + param->thread = CreateThread( NULL, 0, enumSessionsProc, param, 0, NULL ); + + return param; +} + +static HRESULT enumSessionsAsyncWait( EnumSessionsParam *param, DWORD timeout ) +{ + HRESULT hr = 0xdeadbeef; + DWORD waitResult; + + waitResult = WaitForSingleObject( param->thread, timeout ); + CloseHandle( param->thread ); + if ( waitResult == WAIT_OBJECT_0 ) + { + hr = param->hr; + free( param ); + } + + return hr; +} + +#include "pshpack1.h" + +typedef struct +{ + DWORD mixed; + SOCKADDR_IN addr; +} SpHeader; + +typedef struct +{ + DWORD magic; + WORD command; + WORD version; +} MessageHeader; + +typedef struct +{ + MessageHeader header; + GUID appGuid; + DWORD passwordOffset; + DWORD flags; +} EnumSessionsRequest; + +typedef struct +{ + MessageHeader header; + DPSESSIONDESC2 dpsd; + DWORD nameOffset; +} EnumSessionsReply; + +#include "poppack.h" + +#define bindUdp( port ) bindUdp_( __LINE__, port ) +static SOCKET bindUdp_( int line, unsigned short port ) +{ + unsigned long nbio = 1; + SOCKADDR_IN addr; + int wsResult; + SOCKET sock; + + sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); + ok_( __FILE__, line) ( sock != INVALID_SOCKET, "got UDP socket %#Ix.\n", sock ); + + addr.sin_family = AF_INET; + addr.sin_port = htons( port ); + addr.sin_addr.s_addr = htonl( INADDR_ANY ); + wsResult = bind( sock, (SOCKADDR *) &addr, sizeof( addr ) ); + ok_( __FILE__, line)( !wsResult, "bind() returned %d.\n", wsResult ); + + wsResult = ioctlsocket( sock, FIONBIO, &nbio ); + ok_( __FILE__, line)( !wsResult, "ioctlsocket() returned %d.\n", wsResult ); + + return sock; +} + +#define connectTcp( port ) connectTcp_( __LINE__, port ) +static SOCKET connectTcp_( int line, unsigned short port ) +{ + SOCKADDR_IN addr; + int wsResult; + SOCKET sock; + + sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); + ok_( __FILE__, line)( sock != INVALID_SOCKET, "got send socket %#Ix.\n", sock ); + + addr.sin_family = AF_INET; + addr.sin_port = htons( port ); + addr.sin_addr.s_addr = htonl( INADDR_LOOPBACK ); + wsResult = connect( sock, (SOCKADDR *) &addr, sizeof( addr ) ); + todo_wine ok_( __FILE__, line)( !wsResult, "connect returned %d.\n", wsResult ); + if ( wsResult == SOCKET_ERROR ) + { + closesocket( sock ); + return INVALID_SOCKET; + } + + return sock; +} + +#define receiveMessage( sock, buffer, size ) receiveMessage_( __LINE__, sock, buffer, size ) +static int receiveMessage_( int line, SOCKET sock, void *buffer, int size ) +{ + struct timeval timeout; + int recvResult; + int wsResult; + fd_set fds; + + FD_ZERO( &fds ); + FD_SET( sock, &fds ); + timeout.tv_sec = 2; + timeout.tv_usec = 0; + wsResult = select( sock + 1, &fds, NULL, &fds, &timeout ); + ok_( __FILE__, line )( wsResult != SOCKET_ERROR, "select() returned %d.\n", wsResult ); + + memset( buffer, 0xcc, size ); + recvResult = recv( sock, buffer, size, 0 ); + + return recvResult; +} + +#define checkNoMoreMessages( sock ) checkNoMoreMessages_( __LINE__, sock ) +static void checkNoMoreMessages_( int line, SOCKET sock ) +{ + struct timeval timeout; + int wsResult; + fd_set fds; + + FD_ZERO( &fds ); + FD_SET( sock, &fds ); + timeout.tv_sec = 0; + timeout.tv_usec = 100000; + wsResult = select( sock + 1, &fds, NULL, &fds, &timeout ); + ok_( __FILE__, line )( !wsResult, "select() returned %d.\n", wsResult ); +} + +#define checkSpHeader( header, expectedSize, sizeTodo ) checkSpHeader_( __LINE__, header, expectedSize, sizeTodo ) +static unsigned short checkSpHeader_( int line, SpHeader *header, DWORD expectedSize, BOOL sizeTodo ) +{ + todo_wine_if( sizeTodo ) ok_( __FILE__, line )( header->mixed == 0xfab00000 + expectedSize, "got mixed %#lx.\n", + header->mixed ); + ok_( __FILE__, line )( header->addr.sin_family == AF_INET, "got family %d.\n", header->addr.sin_family ); + ok_( __FILE__, line )( 2300 <= ntohs( header->addr.sin_port ) && ntohs( header->addr.sin_port ) < 2350, + "got port %d.\n", ntohs( header->addr.sin_port ) ); + ok_( __FILE__, line )( !header->addr.sin_addr.s_addr, "got address %#lx.\n", header->addr.sin_addr.s_addr ); + + return ntohs( header->addr.sin_port ); +} + +#define checkMessageHeader( header, expectedCommand ) checkMessageHeader_( __LINE__, header, expectedCommand ) +static void checkMessageHeader_( int line, MessageHeader *header, WORD expectedCommand ) +{ + ok_( __FILE__, line )( header->magic == 0x79616c70, "got magic %#lx.\n", header->magic ); + ok_( __FILE__, line )( header->command == expectedCommand, "got command %d.\n", header->command ); +} + +#define receiveEnumSessionsRequest( sock, expectedAppGuid, expectedPassword, expectedFlags ) \ + receiveEnumSessionsRequest_( __LINE__, sock, expectedAppGuid, expectedPassword, expectedFlags ) +static unsigned short receiveEnumSessionsRequest_( int line, SOCKET sock, const GUID *expectedAppGuid, + const WCHAR *expectedPassword, DWORD expectedFlags ) +{ + struct + { + SpHeader spHeader; + EnumSessionsRequest request; + WCHAR password[ 256 ]; + } request; + DWORD expectedPasswordSize; + unsigned short port; + DWORD expectedSize; + int wsResult; + + expectedPasswordSize = expectedPassword ? (lstrlenW( expectedPassword ) + 1) * sizeof( WCHAR ) : 0; + expectedSize = sizeof( request.spHeader ) + sizeof( request.request ) + expectedPasswordSize; + + wsResult = receiveMessage_( line, sock, &request, sizeof( request ) ); + todo_wine ok_( __FILE__, line )( wsResult == expectedSize, "recv() returned %d.\n", + wsResult ); + if ( wsResult == SOCKET_ERROR ) + return 0; + + port = checkSpHeader_( line, &request.spHeader, expectedSize, expectedPassword != NULL ); + checkMessageHeader_( line, &request.request.header, 2 ); + ok_( __FILE__, line )( IsEqualGUID( &request.request.appGuid, expectedAppGuid ), "got app guid %s.\n", + wine_dbgstr_guid( &request.request.appGuid ) ); + if ( expectedPassword ) + { + ok_( __FILE__, line )( request.request.passwordOffset == 32, "got password offset %lu.\n", + request.request.passwordOffset ); + ok_( __FILE__, line )( !lstrcmpW( request.password, expectedPassword ), "got password %s.\n", + wine_dbgstr_w( request.password ) ); + } + else + { + ok_( __FILE__, line )( !request.request.passwordOffset, "got password offset %lu.\n", + request.request.passwordOffset ); + } + ok_( __FILE__, line )( request.request.flags == expectedFlags, "got flags %#lx.\n", request.request.flags ); + + return port; +} + +#define sendEnumSessionsReply( sock, port, dpsd ) sendEnumSessionsReply_( __LINE__, sock, port, dpsd ) +static void sendEnumSessionsReply_( int line, SOCKET sock, unsigned short port, const DPSESSIONDESC2 *dpsd ) +{ + struct + { + SpHeader spHeader; + EnumSessionsReply reply; + WCHAR name[ 256 ]; + } reply = + { + .spHeader = + { + .mixed = 0xfab00000, + .addr = + { + .sin_family = AF_INET, + .sin_port = htons( port ), + }, + }, + .reply = + { + .header = + { + .magic = 0x79616c70, + .command = 1, + .version = 14, + }, + .dpsd = *dpsd, + .nameOffset = sizeof( reply.reply ), + }, + }; + int wsResult; + DWORD size; + + size = sizeof( reply ) + (lstrlenW( dpsd->lpszSessionName ) + 1) * sizeof( WCHAR ); + + reply.spHeader.mixed += size; + reply.reply.dpsd.lpszSessionName = NULL; + reply.reply.dpsd.lpszPassword = NULL; + lstrcpyW( reply.name, dpsd->lpszSessionName ); + + wsResult = send( sock, (char *) &reply, size, 0 ); + ok_( __FILE__, line )( wsResult == size, "send() returned %d.\n", wsResult ); +} + static void init_TCPIP_provider( IDirectPlay4 *pDP, LPCSTR strIPAddressString, WORD port ) {
@@ -1422,7 +1708,388 @@ static IDirectPlay4 *create_session(DPSESSIONDESC2 *lpdpsd)
}
+typedef struct +{ + DPSESSIONDESC2 dpsd; + int actualCount; +} ExpectedSession; + +typedef struct +{ + int line; + ExpectedSession *expectedSessions; + int expectedCount; + int actualCount; + int timeoutCount; + DWORD startTickCount; +} CheckSessionListCallbackData; + +static BOOL CALLBACK checkSessionListCallback( const DPSESSIONDESC2 *thisSd, DWORD *timeout, DWORD flags, void *context ) +{ + CheckSessionListCallbackData *data = context; + ExpectedSession *expectedSession; + int i; + + if ( flags & DPESC_TIMEDOUT ) + { + ++data->timeoutCount; + + if ( data->actualCount >= data->expectedCount ) + return FALSE; + + if ( GetTickCount() - data->startTickCount >= 2000 ) + return FALSE; + + *timeout = 100; + + return TRUE; + } + + ++data->actualCount; + + for ( i = 0; i < data->expectedCount; ++i ) + { + expectedSession = &data->expectedSessions[ i ]; + if ( !IsEqualGUID( &expectedSession->dpsd.guidInstance, &thisSd->guidInstance ) ) + continue; + + ok_( __FILE__, data->line )( !expectedSession->actualCount, "duplicate session %s.\n", + wine_dbgstr_guid( &thisSd->guidInstance ) ); + + ok_( __FILE__, data->line )( thisSd->dwSize == expectedSession->dpsd.dwSize, "got size %lu.\n", + thisSd->dwSize ); + ok_( __FILE__, data->line )( thisSd->dwFlags == expectedSession->dpsd.dwFlags, "got flags %#lx.\n", + thisSd->dwFlags ); + ok_( __FILE__, data->line )( IsEqualGUID( &thisSd->guidApplication, &expectedSession->dpsd.guidApplication ), + "got application GUID %s.\n", wine_dbgstr_guid( &thisSd->guidApplication ) ); + ok_( __FILE__, data->line )( thisSd->dwMaxPlayers == expectedSession->dpsd.dwMaxPlayers, + "got current player count %lu.\n", thisSd->dwMaxPlayers ); + ok_( __FILE__, data->line )( thisSd->dwCurrentPlayers == expectedSession->dpsd.dwCurrentPlayers, + "got max player count %lu.\n", thisSd->dwCurrentPlayers ); + ok_( __FILE__, data->line )( !strcmp( thisSd->lpszSessionNameA, expectedSession->dpsd.lpszSessionNameA ), + "got session name %s.\n", wine_dbgstr_a( thisSd->lpszSessionNameA ) ); + ok_( __FILE__, data->line )( !thisSd->lpszPasswordA, "got password %s.\n", + wine_dbgstr_a( thisSd->lpszPasswordA ) ); + ok_( __FILE__, data->line )( thisSd->dwReserved1 == expectedSession->dpsd.dwReserved1, "got reserved1 %#lx.\n", + thisSd->dwReserved1 ); + ok_( __FILE__, data->line )( thisSd->dwReserved2 == expectedSession->dpsd.dwReserved2, "got reserved2 %#lx.\n", + thisSd->dwReserved2 ); + ok_( __FILE__, data->line )( thisSd->dwUser1 == expectedSession->dpsd.dwUser1, "got user1 %#lx.\n", + thisSd->dwUser1 ); + ok_( __FILE__, data->line )( thisSd->dwUser2 == expectedSession->dpsd.dwUser2, "got user2 %#lx.\n", + thisSd->dwUser2 ); + ok_( __FILE__, data->line )( thisSd->dwUser3 == expectedSession->dpsd.dwUser3, "got user3 %#lx.\n", + thisSd->dwUser3 ); + ok_( __FILE__, data->line )( thisSd->dwUser4 == expectedSession->dpsd.dwUser4, "got user4 %#lx.\n", + thisSd->dwUser4 ); + + ++expectedSession->actualCount; + + return TRUE; + } + + ok_( __FILE__, data->line )( 0, "unexpected session %s.\n", wine_dbgstr_guid( &thisSd->guidInstance ) ); + + return TRUE; +} + +#define check_EnumSessions( dp, dpsd, flags, expectedHr, expectedSessionCount, timeoutExpected, \ + requestExpected, expectedPassword, replyCount, hrTodo, timeoutTodo ) \ + check_EnumSessions_( __LINE__, dp, dpsd, flags, expectedHr, expectedSessionCount, timeoutExpected, \ + requestExpected, expectedPassword, replyCount, hrTodo, timeoutTodo ) +static void check_EnumSessions_( int line, IDirectPlay4 *dp, DPSESSIONDESC2 *dpsd, DWORD flags, HRESULT expectedHr, + DWORD expectedSessionCount, BOOL timeoutExpected, BOOL requestExpected, + const WCHAR *expectedPassword, DWORD replyCount, BOOL hrTodo, BOOL timeoutTodo ) +{ + DPSESSIONDESC2 replyDpsds[] = + { + { + .dwSize = sizeof( DPSESSIONDESC2 ), + .dwFlags = 0, + .guidInstance = appGuid, + .guidApplication = appGuid, + .dwMaxPlayers = 10, + .dwCurrentPlayers = 0, + .lpszSessionName = (WCHAR *) L"normal", + .dwReserved1 = 0x11223344, + .dwReserved2 = 0, + .dwUser1 = 1, + .dwUser2 = 2, + .dwUser3 = 3, + .dwUser4 = 4, + }, + { + .dwSize = sizeof( DPSESSIONDESC2 ), + .dwFlags = DPSESSION_JOINDISABLED | DPSESSION_PASSWORDREQUIRED | DPSESSION_PRIVATE, + .guidInstance = appGuid2, + .guidApplication = appGuid2, + .dwMaxPlayers = 10, + .dwCurrentPlayers = 10, + .lpszSessionName = (WCHAR *) L"private", + .dwReserved1 = 0xaabbccdd, + .dwReserved2 = 0, + .dwUser1 = 5, + .dwUser2 = 6, + .dwUser3 = 7, + .dwUser4 = 8, + }, + }; + ExpectedSession expectedSessions[ ARRAYSIZE( replyDpsds ) ]; + CheckSessionListCallbackData callbackData; + EnumSessionsParam *param; + unsigned short port = 0; + WSADATA wsaData; + SOCKET enumSock; + int wsResult; + SOCKET sock; + HRESULT hr; + int i; + + wsResult = WSAStartup( MAKEWORD( 2, 0 ), &wsaData ); + ok_( __FILE__, line )( !wsResult, "WSAStartup() returned %d.\n", wsResult ); + + enumSock = bindUdp_( line, 47624 ); + + memset( &expectedSessions, 0, sizeof( expectedSessions ) ); + expectedSessions[ 0 ].dpsd = replyDpsds [ 0 ]; + expectedSessions[ 0 ].dpsd.lpszSessionNameA = (char *) "normal"; + expectedSessions[ 1 ].dpsd = replyDpsds [ 1 ]; + expectedSessions[ 1 ].dpsd.lpszSessionNameA = (char *) "private"; + + memset( &callbackData, 0, sizeof( callbackData ) ); + callbackData.startTickCount = GetTickCount(); + callbackData.expectedSessions = expectedSessions; + callbackData.expectedCount = expectedSessionCount; + + param = enumSessionsAsync( dp, dpsd, 100, checkSessionListCallback, &callbackData, flags ); + + if ( requestExpected ) + port = receiveEnumSessionsRequest_( line, enumSock, &appGuid, expectedPassword, flags ); + + for ( i = 0; i < replyCount; ++i ) + { + sock = connectTcp_( line, port ); + if ( sock == INVALID_SOCKET ) + continue; + + sendEnumSessionsReply_( line, sock, 2349 - i, &replyDpsds[ i ] ); + + closesocket( sock ); + } + + checkNoMoreMessages_( line, enumSock ); + + hr = enumSessionsAsyncWait( param, 2000 ); + todo_wine_if( hrTodo ) ok_( __FILE__, line )( hr == expectedHr, "got hr %#lx.\n", hr ); + + todo_wine_if( expectedSessionCount ) ok_( __FILE__, line )( callbackData.actualCount == callbackData.expectedCount, + "got session count %d.\n", callbackData.actualCount ); + todo_wine_if( timeoutTodo ) ok_( __FILE__, line )( !!callbackData.timeoutCount == timeoutExpected, + "got timeout count %d.\n", callbackData.timeoutCount ); + + closesocket( enumSock ); + WSACleanup(); +} + +#define check_EnumSessions_async( dpsd, dp ) check_EnumSessions_async_( __LINE__, dpsd, dp ) +static void check_EnumSessions_async_( int line, DPSESSIONDESC2 *dpsd, IDirectPlay4 *dp ) +{ + DPSESSIONDESC2 replyDpsds[] = + { + { + .dwSize = sizeof( DPSESSIONDESC2 ), + .dwFlags = 0, + .guidInstance = appGuid, + .guidApplication = appGuid, + .dwMaxPlayers = 10, + .dwCurrentPlayers = 0, + .lpszSessionName = (WCHAR *) L"normal", + .dwReserved1 = 0x11223344, + .dwReserved2 = 0, + .dwUser1 = 1, + .dwUser2 = 2, + .dwUser3 = 3, + .dwUser4 = 4, + }, + { + .dwSize = sizeof( DPSESSIONDESC2 ), + .dwFlags = DPSESSION_JOINDISABLED | DPSESSION_PASSWORDREQUIRED | DPSESSION_PRIVATE, + .guidInstance = appGuid2, + .guidApplication = appGuid2, + .dwMaxPlayers = 10, + .dwCurrentPlayers = 10, + .lpszSessionName = (WCHAR *) L"private", + .dwReserved1 = 0xaabbccdd, + .dwReserved2 = 0, + .dwUser1 = 5, + .dwUser2 = 6, + .dwUser3 = 7, + .dwUser4 = 8, + }, + }; + CheckSessionListCallbackData callbackData; + ExpectedSession expectedSessions[ 2 ]; + EnumSessionsParam *param; + unsigned short port; + SOCKET enumSock; + SOCKET sock; + HRESULT hr; + int i; + + enumSock = bindUdp_( line, 47624 ); + + memset( expectedSessions, 0, sizeof( expectedSessions ) ); + expectedSessions[ 0 ].dpsd = replyDpsds [ 0 ]; + expectedSessions[ 0 ].dpsd.lpszSessionNameA = (char *) "normal"; + + memset( &callbackData, 0, sizeof( callbackData ) ); + callbackData.expectedSessions = expectedSessions; + callbackData.expectedCount = 1; + callbackData.startTickCount = GetTickCount(); + + /* Do a sync enumeration first to fill the cache */ + param = enumSessionsAsync( dp, dpsd, 100, checkSessionListCallback, &callbackData, 0 ); + + port = receiveEnumSessionsRequest_( line, enumSock, &appGuid, NULL, 0 ); + + sock = connectTcp_( line, port ); + + if ( sock != INVALID_SOCKET ) + { + sendEnumSessionsReply_( line, sock, 2349, &replyDpsds[ 0 ] ); + + closesocket( sock ); + } + + checkNoMoreMessages_( line, enumSock ); + + hr = enumSessionsAsyncWait( param, 2000 ); + todo_wine ok_( __FILE__, line )( hr == DP_OK, "got hr %#lx.\n", hr ); + + todo_wine ok_( __FILE__, line )( callbackData.actualCount == callbackData.expectedCount, "got session count %d.\n", + callbackData.actualCount ); + ok_( __FILE__, line )( callbackData.timeoutCount, "got timeout count %d.\n", callbackData.timeoutCount ); + + memset( expectedSessions, 0, sizeof( expectedSessions ) ); + expectedSessions[ 0 ].dpsd = replyDpsds [ 0 ]; + expectedSessions[ 0 ].dpsd.lpszSessionNameA = (char *) "normal"; + + memset( &callbackData, 0, sizeof( callbackData ) ); + callbackData.expectedSessions = expectedSessions; + callbackData.expectedCount = 1; + callbackData.startTickCount = GetTickCount(); + + /* Read cache of last sync enumeration */ + param = enumSessionsAsync( dp, dpsd, 100, checkSessionListCallback, &callbackData, DPENUMSESSIONS_ASYNC ); + + receiveEnumSessionsRequest_( line, enumSock, &appGuid, NULL, DPENUMSESSIONS_ASYNC ); + + hr = enumSessionsAsyncWait( param, 2000 ); + todo_wine ok_( __FILE__, line )( hr == DP_OK, "got hr %#lx.\n", hr ); + + todo_wine ok_( __FILE__, line )( callbackData.actualCount == callbackData.expectedCount, "got session count %d.\n", + callbackData.actualCount ); + ok_( __FILE__, line )( callbackData.timeoutCount, "got timeout count %d.\n", callbackData.timeoutCount ); + + /* Check that requests are sent periodically */ + for ( i = 0; i < 2; ++i ) + port = receiveEnumSessionsRequest_( line, enumSock, &appGuid, NULL, DPENUMSESSIONS_ASYNC ); + + for ( i = 0; i < ARRAYSIZE( replyDpsds ); ++i ) + { + sock = connectTcp_( line, port ); + if ( sock == INVALID_SOCKET ) + continue; + + sendEnumSessionsReply_( line, sock, 2349 - i, &replyDpsds[ i ] ); + + closesocket( sock ); + } + + memset( expectedSessions, 0, sizeof( expectedSessions ) ); + expectedSessions[ 0 ].dpsd = replyDpsds [ 0 ]; + expectedSessions[ 0 ].dpsd.lpszSessionNameA = (char *) "normal"; + expectedSessions[ 1 ].dpsd = replyDpsds [ 1 ]; + expectedSessions[ 1 ].dpsd.lpszSessionNameA = (char *) "private"; + + memset( &callbackData, 0, sizeof( callbackData ) ); + callbackData.expectedSessions = expectedSessions; + callbackData.expectedCount = ARRAYSIZE( expectedSessions ); + callbackData.startTickCount = GetTickCount(); + + /* Retrieve results */ + param = enumSessionsAsync( dp, dpsd, 100, checkSessionListCallback, &callbackData, DPENUMSESSIONS_ASYNC ); + hr = enumSessionsAsyncWait( param, 2000 ); + todo_wine ok_( __FILE__, line )( hr == DP_OK, "got hr %#lx.\n", hr ); + + todo_wine ok_( __FILE__, line )( callbackData.actualCount == callbackData.expectedCount, "got session count %d.\n", + callbackData.actualCount ); + ok_( __FILE__, line )( callbackData.timeoutCount, "got timeout count %d.\n", callbackData.timeoutCount ); + + memset( &callbackData, 0, sizeof( callbackData ) ); + callbackData.expectedSessions = NULL; + callbackData.expectedCount = 0; + callbackData.startTickCount = GetTickCount(); + + /* Stop enumeration */ + param = enumSessionsAsync( dp, dpsd, 100, checkSessionListCallback, &callbackData, DPENUMSESSIONS_STOPASYNC ); + hr = enumSessionsAsyncWait( param, 2000 ); + ok_( __FILE__, line )( hr == DP_OK, "got hr %#lx.\n", hr ); + + ok_( __FILE__, line )( !callbackData.actualCount, "got session count %d.\n", callbackData.actualCount ); + todo_wine ok_( __FILE__, line )( callbackData.timeoutCount, "got timeout count %d.\n", callbackData.timeoutCount ); + + closesocket( enumSock ); +} + static void test_EnumSessions(void) +{ + DPSESSIONDESC2 appGuidDpsd = + { + .dwSize = sizeof( DPSESSIONDESC2 ), + .guidApplication = appGuid, + .guidInstance = appGuid, + }; + DPSESSIONDESC2 dpsd; + IDirectPlay4 *dp; + HRESULT hr; + + hr = CoCreateInstance( &CLSID_DirectPlay, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectPlay4A, (void **) &dp ); + ok( hr == DP_OK, "got hr %#lx.\n", hr ); + + /* Service provider not initialized */ + check_EnumSessions( dp, &appGuidDpsd, 0, DPERR_UNINITIALIZED, 0, FALSE, FALSE, NULL, 0, FALSE, FALSE ); + + init_TCPIP_provider( dp, "127.0.0.1", 0 ); + + /* Session with no size */ + dpsd = appGuidDpsd; + dpsd.dwSize = 0; + check_EnumSessions( dp, &dpsd, 0, DPERR_INVALIDPARAMS, 0, FALSE, FALSE, NULL, 0, TRUE, TRUE ); + + /* No sessions */ + check_EnumSessions( dp, &appGuidDpsd, 0, DP_OK, 0, TRUE, TRUE, NULL, 0, TRUE, FALSE ); + + /* Invalid params */ + check_EnumSessions( dp, &appGuidDpsd, -1, DPERR_INVALIDPARAMS, 0, FALSE, FALSE, NULL, 0, TRUE, FALSE ); + check_EnumSessions( dp, NULL, 0, DPERR_INVALIDPARAMS, 0, FALSE, FALSE, NULL, 0, FALSE, FALSE ); + + /* All sessions are enumerated regardless of flags */ + check_EnumSessions( dp, &appGuidDpsd, 0, DP_OK, 2, TRUE, TRUE, NULL, 2, TRUE, FALSE ); + check_EnumSessions( dp, &appGuidDpsd, DPENUMSESSIONS_AVAILABLE, DP_OK, 2, TRUE, TRUE, NULL, 2, TRUE, FALSE ); + + /* Async enumeration */ + check_EnumSessions_async( &appGuidDpsd, dp ); + + /* Enumeration with password */ + dpsd = appGuidDpsd; + dpsd.lpszPasswordA = (char *) "password"; + check_EnumSessions( dp, &dpsd, 0, DP_OK, 2, TRUE, TRUE, L"password", 2, TRUE, FALSE ); + + IDirectPlayX_Release( dp ); +} + +static void test_interactive_EnumSessions(void) {
#define N_SESSIONS 6 @@ -6936,6 +7603,7 @@ START_TEST(dplayx) test_InitializeConnection(); test_GetCaps(); test_EnumAddressTypes(); + test_EnumSessions();
if (!winetest_interactive) { @@ -6947,8 +7615,8 @@ START_TEST(dplayx)
/* test_Open() takes almost a minute, */ test_Open(); - /* test_EnumSession takes three minutes */ - test_EnumSessions(); + /* test_interactive_EnumSessions takes three minutes */ + test_interactive_EnumSessions(); test_SessionDesc();
/* test_CreatePlayer() takes over a minute */
From: Anton Baskanov baskanov@gmail.com
--- dlls/dplayx/dplay.c | 3 +++ dlls/dplayx/tests/dplayx.c | 26 +++++++++++++------------- 2 files changed, 16 insertions(+), 13 deletions(-)
diff --git a/dlls/dplayx/dplay.c b/dlls/dplayx/dplay.c index 8f28a8a9837..854c266aa4f 100644 --- a/dlls/dplayx/dplay.c +++ b/dlls/dplayx/dplay.c @@ -2419,6 +2419,9 @@ static HRESULT WINAPI IDirectPlay4Impl_EnumSessions( IDirectPlay4 *iface, DPSESS if ( !sdesc ) return DPERR_INVALIDPARAM;
+ if ( sdesc->dwSize != sizeof( DPSESSIONDESC2 ) ) + return DPERR_INVALIDPARAM; + /* Can't enumerate if the interface is already open */ if ( This->dp2->bConnectionOpen ) return DPERR_GENERIC; diff --git a/dlls/dplayx/tests/dplayx.c b/dlls/dplayx/tests/dplayx.c index fcc4eb7de5f..94ce3581046 100644 --- a/dlls/dplayx/tests/dplayx.c +++ b/dlls/dplayx/tests/dplayx.c @@ -1794,12 +1794,12 @@ static BOOL CALLBACK checkSessionListCallback( const DPSESSIONDESC2 *thisSd, DWO }
#define check_EnumSessions( dp, dpsd, flags, expectedHr, expectedSessionCount, timeoutExpected, \ - requestExpected, expectedPassword, replyCount, hrTodo, timeoutTodo ) \ + requestExpected, expectedPassword, replyCount, hrTodo ) \ check_EnumSessions_( __LINE__, dp, dpsd, flags, expectedHr, expectedSessionCount, timeoutExpected, \ - requestExpected, expectedPassword, replyCount, hrTodo, timeoutTodo ) + requestExpected, expectedPassword, replyCount, hrTodo ) static void check_EnumSessions_( int line, IDirectPlay4 *dp, DPSESSIONDESC2 *dpsd, DWORD flags, HRESULT expectedHr, DWORD expectedSessionCount, BOOL timeoutExpected, BOOL requestExpected, - const WCHAR *expectedPassword, DWORD replyCount, BOOL hrTodo, BOOL timeoutTodo ) + const WCHAR *expectedPassword, DWORD replyCount, BOOL hrTodo ) { DPSESSIONDESC2 replyDpsds[] = { @@ -1884,8 +1884,8 @@ static void check_EnumSessions_( int line, IDirectPlay4 *dp, DPSESSIONDESC2 *dps
todo_wine_if( expectedSessionCount ) ok_( __FILE__, line )( callbackData.actualCount == callbackData.expectedCount, "got session count %d.\n", callbackData.actualCount ); - todo_wine_if( timeoutTodo ) ok_( __FILE__, line )( !!callbackData.timeoutCount == timeoutExpected, - "got timeout count %d.\n", callbackData.timeoutCount ); + ok_( __FILE__, line )( !!callbackData.timeoutCount == timeoutExpected, "got timeout count %d.\n", + callbackData.timeoutCount );
closesocket( enumSock ); WSACleanup(); @@ -2058,25 +2058,25 @@ static void test_EnumSessions(void) ok( hr == DP_OK, "got hr %#lx.\n", hr );
/* Service provider not initialized */ - check_EnumSessions( dp, &appGuidDpsd, 0, DPERR_UNINITIALIZED, 0, FALSE, FALSE, NULL, 0, FALSE, FALSE ); + check_EnumSessions( dp, &appGuidDpsd, 0, DPERR_UNINITIALIZED, 0, FALSE, FALSE, NULL, 0, FALSE );
init_TCPIP_provider( dp, "127.0.0.1", 0 );
/* Session with no size */ dpsd = appGuidDpsd; dpsd.dwSize = 0; - check_EnumSessions( dp, &dpsd, 0, DPERR_INVALIDPARAMS, 0, FALSE, FALSE, NULL, 0, TRUE, TRUE ); + check_EnumSessions( dp, &dpsd, 0, DPERR_INVALIDPARAMS, 0, FALSE, FALSE, NULL, 0, FALSE );
/* No sessions */ - check_EnumSessions( dp, &appGuidDpsd, 0, DP_OK, 0, TRUE, TRUE, NULL, 0, TRUE, FALSE ); + check_EnumSessions( dp, &appGuidDpsd, 0, DP_OK, 0, TRUE, TRUE, NULL, 0, TRUE );
/* Invalid params */ - check_EnumSessions( dp, &appGuidDpsd, -1, DPERR_INVALIDPARAMS, 0, FALSE, FALSE, NULL, 0, TRUE, FALSE ); - check_EnumSessions( dp, NULL, 0, DPERR_INVALIDPARAMS, 0, FALSE, FALSE, NULL, 0, FALSE, FALSE ); + check_EnumSessions( dp, &appGuidDpsd, -1, DPERR_INVALIDPARAMS, 0, FALSE, FALSE, NULL, 0, TRUE ); + check_EnumSessions( dp, NULL, 0, DPERR_INVALIDPARAMS, 0, FALSE, FALSE, NULL, 0, FALSE );
/* All sessions are enumerated regardless of flags */ - check_EnumSessions( dp, &appGuidDpsd, 0, DP_OK, 2, TRUE, TRUE, NULL, 2, TRUE, FALSE ); - check_EnumSessions( dp, &appGuidDpsd, DPENUMSESSIONS_AVAILABLE, DP_OK, 2, TRUE, TRUE, NULL, 2, TRUE, FALSE ); + check_EnumSessions( dp, &appGuidDpsd, 0, DP_OK, 2, TRUE, TRUE, NULL, 2, TRUE ); + check_EnumSessions( dp, &appGuidDpsd, DPENUMSESSIONS_AVAILABLE, DP_OK, 2, TRUE, TRUE, NULL, 2, TRUE );
/* Async enumeration */ check_EnumSessions_async( &appGuidDpsd, dp ); @@ -2084,7 +2084,7 @@ static void test_EnumSessions(void) /* Enumeration with password */ dpsd = appGuidDpsd; dpsd.lpszPasswordA = (char *) "password"; - check_EnumSessions( dp, &dpsd, 0, DP_OK, 2, TRUE, TRUE, L"password", 2, TRUE, FALSE ); + check_EnumSessions( dp, &dpsd, 0, DP_OK, 2, TRUE, TRUE, L"password", 2, TRUE );
IDirectPlayX_Release( dp ); }
From: Anton Baskanov baskanov@gmail.com
--- dlls/dpwsockx/dpwsockx_main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/dlls/dpwsockx/dpwsockx_main.c b/dlls/dpwsockx/dpwsockx_main.c index 06ef63674f8..239f94b6ea6 100644 --- a/dlls/dpwsockx/dpwsockx_main.c +++ b/dlls/dpwsockx/dpwsockx_main.c @@ -124,8 +124,11 @@ static HRESULT WINAPI DPWSCB_CloseEx( LPDPSP_CLOSEDATA data )
static HRESULT WINAPI DPWSCB_ShutdownEx( LPDPSP_SHUTDOWNDATA data ) { - FIXME( "(%p) stub\n", data->lpISP ); - return DPERR_UNSUPPORTED; + TRACE( "(%p)\n", data->lpISP ); + + WSACleanup(); + + return DP_OK; }
static HRESULT WINAPI DPWSCB_GetAddressChoices( LPDPSP_GETADDRESSCHOICESDATA data )
From: Anton Baskanov baskanov@gmail.com
--- dlls/dplayx/tests/dplayx.c | 14 ++--- dlls/dpwsockx/dpwsockx_dll.h | 7 ++- dlls/dpwsockx/dpwsockx_main.c | 113 +++++++++++++++++++++++++++++++++- 3 files changed, 123 insertions(+), 11 deletions(-)
diff --git a/dlls/dplayx/tests/dplayx.c b/dlls/dplayx/tests/dplayx.c index 94ce3581046..0447ca90602 100644 --- a/dlls/dplayx/tests/dplayx.c +++ b/dlls/dplayx/tests/dplayx.c @@ -1964,7 +1964,7 @@ static void check_EnumSessions_async_( int line, DPSESSIONDESC2 *dpsd, IDirectPl checkNoMoreMessages_( line, enumSock );
hr = enumSessionsAsyncWait( param, 2000 ); - todo_wine ok_( __FILE__, line )( hr == DP_OK, "got hr %#lx.\n", hr ); + ok_( __FILE__, line )( hr == DP_OK, "got hr %#lx.\n", hr );
todo_wine ok_( __FILE__, line )( callbackData.actualCount == callbackData.expectedCount, "got session count %d.\n", callbackData.actualCount ); @@ -1985,7 +1985,7 @@ static void check_EnumSessions_async_( int line, DPSESSIONDESC2 *dpsd, IDirectPl receiveEnumSessionsRequest_( line, enumSock, &appGuid, NULL, DPENUMSESSIONS_ASYNC );
hr = enumSessionsAsyncWait( param, 2000 ); - todo_wine ok_( __FILE__, line )( hr == DP_OK, "got hr %#lx.\n", hr ); + ok_( __FILE__, line )( hr == DP_OK, "got hr %#lx.\n", hr );
todo_wine ok_( __FILE__, line )( callbackData.actualCount == callbackData.expectedCount, "got session count %d.\n", callbackData.actualCount ); @@ -2020,7 +2020,7 @@ static void check_EnumSessions_async_( int line, DPSESSIONDESC2 *dpsd, IDirectPl /* Retrieve results */ param = enumSessionsAsync( dp, dpsd, 100, checkSessionListCallback, &callbackData, DPENUMSESSIONS_ASYNC ); hr = enumSessionsAsyncWait( param, 2000 ); - todo_wine ok_( __FILE__, line )( hr == DP_OK, "got hr %#lx.\n", hr ); + ok_( __FILE__, line )( hr == DP_OK, "got hr %#lx.\n", hr );
todo_wine ok_( __FILE__, line )( callbackData.actualCount == callbackData.expectedCount, "got session count %d.\n", callbackData.actualCount ); @@ -2068,15 +2068,15 @@ static void test_EnumSessions(void) check_EnumSessions( dp, &dpsd, 0, DPERR_INVALIDPARAMS, 0, FALSE, FALSE, NULL, 0, FALSE );
/* No sessions */ - check_EnumSessions( dp, &appGuidDpsd, 0, DP_OK, 0, TRUE, TRUE, NULL, 0, TRUE ); + check_EnumSessions( dp, &appGuidDpsd, 0, DP_OK, 0, TRUE, TRUE, NULL, 0, FALSE );
/* Invalid params */ check_EnumSessions( dp, &appGuidDpsd, -1, DPERR_INVALIDPARAMS, 0, FALSE, FALSE, NULL, 0, TRUE ); check_EnumSessions( dp, NULL, 0, DPERR_INVALIDPARAMS, 0, FALSE, FALSE, NULL, 0, FALSE );
/* All sessions are enumerated regardless of flags */ - check_EnumSessions( dp, &appGuidDpsd, 0, DP_OK, 2, TRUE, TRUE, NULL, 2, TRUE ); - check_EnumSessions( dp, &appGuidDpsd, DPENUMSESSIONS_AVAILABLE, DP_OK, 2, TRUE, TRUE, NULL, 2, TRUE ); + check_EnumSessions( dp, &appGuidDpsd, 0, DP_OK, 2, TRUE, TRUE, NULL, 2, FALSE ); + check_EnumSessions( dp, &appGuidDpsd, DPENUMSESSIONS_AVAILABLE, DP_OK, 2, TRUE, TRUE, NULL, 2, FALSE );
/* Async enumeration */ check_EnumSessions_async( &appGuidDpsd, dp ); @@ -2084,7 +2084,7 @@ static void test_EnumSessions(void) /* Enumeration with password */ dpsd = appGuidDpsd; dpsd.lpszPasswordA = (char *) "password"; - check_EnumSessions( dp, &dpsd, 0, DP_OK, 2, TRUE, TRUE, L"password", 2, TRUE ); + check_EnumSessions( dp, &dpsd, 0, DP_OK, 2, TRUE, TRUE, L"password", 2, FALSE );
IDirectPlayX_Release( dp ); } diff --git a/dlls/dpwsockx/dpwsockx_dll.h b/dlls/dpwsockx/dpwsockx_dll.h index fbbd825e343..477adb86fcd 100644 --- a/dlls/dpwsockx/dpwsockx_dll.h +++ b/dlls/dpwsockx/dpwsockx_dll.h @@ -37,7 +37,12 @@
typedef struct tagDPWS_DATA { - LPDIRECTPLAYSP lpISP; + LPDIRECTPLAYSP lpISP; + + SOCKET tcpSock; + SOCKADDR_IN tcpAddr; + + BOOL started; } DPWS_DATA, *LPDPWS_DATA;
#include "pshpack1.h" diff --git a/dlls/dpwsockx/dpwsockx_main.c b/dlls/dpwsockx/dpwsockx_main.c index 239f94b6ea6..74eea68f2fc 100644 --- a/dlls/dpwsockx/dpwsockx_main.c +++ b/dlls/dpwsockx/dpwsockx_main.c @@ -30,12 +30,98 @@
WINE_DEFAULT_DEBUG_CHANNEL(dplay);
+#define DPWS_START_TCP_PORT 2300 +#define DPWS_END_TCP_PORT 2350 + +static HRESULT DPWS_BindToFreePort( SOCKET sock, SOCKADDR_IN *addr, int startPort, int endPort ) +{ + int port; + + memset( addr, 0, sizeof( *addr ) ); + addr->sin_family = AF_INET; + addr->sin_addr.s_addr = htonl( INADDR_ANY ); + + for ( port = startPort; port < endPort; ++port ) + { + addr->sin_port = htons( port ); + + if ( SOCKET_ERROR != bind( sock, (SOCKADDR *) addr, sizeof( *addr ) ) ) + return DP_OK; + + if ( WSAGetLastError() == WSAEADDRINUSE ) + continue; + + ERR( "bind() failed\n" ); + return DPERR_UNAVAILABLE; + } + + ERR( "no free ports\n" ); + return DPERR_UNAVAILABLE; +} + +static HRESULT DPWS_Start( DPWS_DATA *dpwsData ) +{ + HRESULT hr; + + if ( dpwsData->started ) + return S_OK; + + dpwsData->tcpSock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); + if ( dpwsData->tcpSock == INVALID_SOCKET ) + { + ERR( "socket() failed\n" ); + return DPERR_UNAVAILABLE; + } + + hr = DPWS_BindToFreePort( dpwsData->tcpSock, &dpwsData->tcpAddr, DPWS_START_TCP_PORT, + DPWS_END_TCP_PORT ); + if ( FAILED( hr ) ) + { + closesocket( dpwsData->tcpSock ); + return hr; + } + + if ( SOCKET_ERROR == listen( dpwsData->tcpSock, SOMAXCONN ) ) + { + ERR( "listen() failed\n" ); + closesocket( dpwsData->tcpSock ); + return DPERR_UNAVAILABLE; + } + + dpwsData->started = TRUE; + + return S_OK; +} + +static void DPWS_Stop( DPWS_DATA *dpwsData ) +{ + if ( !dpwsData->started ) + return; + + dpwsData->started = FALSE; + + closesocket( dpwsData->tcpSock ); +} + static HRESULT WINAPI DPWSCB_EnumSessions( LPDPSP_ENUMSESSIONSDATA data ) { + DPWS_DATA *dpwsData; + DWORD dpwsDataSize; + HRESULT hr; + FIXME( "(%p,%ld,%p,%u) stub\n", data->lpMessage, data->dwMessageSize, data->lpISP, data->bReturnStatus ); - return DPERR_UNSUPPORTED; + + hr = IDirectPlaySP_GetSPData( data->lpISP, (void **)&dpwsData, &dpwsDataSize, DPSET_LOCAL ); + if ( FAILED( hr ) ) + return hr; + + hr = DPWS_Start( dpwsData ); + if ( FAILED (hr) ) + return hr; + + return S_OK; }
static HRESULT WINAPI DPWSCB_Reply( LPDPSP_REPLYDATA data ) @@ -118,14 +204,35 @@ static HRESULT WINAPI DPWSCB_Open( LPDPSP_OPENDATA data )
static HRESULT WINAPI DPWSCB_CloseEx( LPDPSP_CLOSEDATA data ) { - FIXME( "(%p) stub\n", data->lpISP ); - return DPERR_UNSUPPORTED; + DPWS_DATA *dpwsData; + DWORD dpwsDataSize; + HRESULT hr; + + TRACE( "(%p)\n", data->lpISP ); + + hr = IDirectPlaySP_GetSPData( data->lpISP, (void **) &dpwsData, &dpwsDataSize, DPSET_LOCAL ); + if ( FAILED( hr ) ) + return hr; + + DPWS_Stop( dpwsData ); + + return DP_OK; }
static HRESULT WINAPI DPWSCB_ShutdownEx( LPDPSP_SHUTDOWNDATA data ) { + DPWS_DATA *dpwsData; + DWORD dpwsDataSize; + HRESULT hr; + TRACE( "(%p)\n", data->lpISP );
+ hr = IDirectPlaySP_GetSPData( data->lpISP, (void **) &dpwsData, &dpwsDataSize, DPSET_LOCAL ); + if ( FAILED( hr ) ) + return hr; + + DPWS_Stop( dpwsData ); + WSACleanup();
return DP_OK;
From: Anton Baskanov baskanov@gmail.com
--- dlls/dplayx/tests/dplayx.c | 19 ++++++--------- dlls/dpwsockx/dpwsockx_main.c | 46 ++++++++++++++++++++++++++++++++--- 2 files changed, 50 insertions(+), 15 deletions(-)
diff --git a/dlls/dplayx/tests/dplayx.c b/dlls/dplayx/tests/dplayx.c index 0447ca90602..694a5edbc8c 100644 --- a/dlls/dplayx/tests/dplayx.c +++ b/dlls/dplayx/tests/dplayx.c @@ -784,12 +784,7 @@ static SOCKET connectTcp_( int line, unsigned short port ) addr.sin_port = htons( port ); addr.sin_addr.s_addr = htonl( INADDR_LOOPBACK ); wsResult = connect( sock, (SOCKADDR *) &addr, sizeof( addr ) ); - todo_wine ok_( __FILE__, line)( !wsResult, "connect returned %d.\n", wsResult ); - if ( wsResult == SOCKET_ERROR ) - { - closesocket( sock ); - return INVALID_SOCKET; - } + ok_( __FILE__, line)( !wsResult, "connect returned %d.\n", wsResult );
return sock; } @@ -870,8 +865,8 @@ static unsigned short receiveEnumSessionsRequest_( int line, SOCKET sock, const expectedSize = sizeof( request.spHeader ) + sizeof( request.request ) + expectedPasswordSize;
wsResult = receiveMessage_( line, sock, &request, sizeof( request ) ); - todo_wine ok_( __FILE__, line )( wsResult == expectedSize, "recv() returned %d.\n", - wsResult ); + todo_wine_if( expectedPassword ) ok_( __FILE__, line )( wsResult == expectedSize, "recv() returned %d.\n", + wsResult ); if ( wsResult == SOCKET_ERROR ) return 0;
@@ -881,10 +876,10 @@ static unsigned short receiveEnumSessionsRequest_( int line, SOCKET sock, const wine_dbgstr_guid( &request.request.appGuid ) ); if ( expectedPassword ) { - ok_( __FILE__, line )( request.request.passwordOffset == 32, "got password offset %lu.\n", - request.request.passwordOffset ); - ok_( __FILE__, line )( !lstrcmpW( request.password, expectedPassword ), "got password %s.\n", - wine_dbgstr_w( request.password ) ); + todo_wine ok_( __FILE__, line )( request.request.passwordOffset == 32, "got password offset %lu.\n", + request.request.passwordOffset ); + todo_wine ok_( __FILE__, line )( !lstrcmpW( request.password, expectedPassword ), "got password %s.\n", + wine_dbgstr_w( request.password ) ); } else { diff --git a/dlls/dpwsockx/dpwsockx_main.c b/dlls/dpwsockx/dpwsockx_main.c index 74eea68f2fc..4a969b1711e 100644 --- a/dlls/dpwsockx/dpwsockx_main.c +++ b/dlls/dpwsockx/dpwsockx_main.c @@ -30,6 +30,7 @@
WINE_DEFAULT_DEBUG_CHANNEL(dplay);
+#define DPWS_PORT 47624 #define DPWS_START_TCP_PORT 2300 #define DPWS_END_TCP_PORT 2350
@@ -105,15 +106,19 @@ static void DPWS_Stop( DPWS_DATA *dpwsData )
static HRESULT WINAPI DPWSCB_EnumSessions( LPDPSP_ENUMSESSIONSDATA data ) { + DPSP_MSG_HEADER *header = (DPSP_MSG_HEADER *) data->lpMessage; DPWS_DATA *dpwsData; DWORD dpwsDataSize; + SOCKADDR_IN addr; + BOOL true = TRUE; + SOCKET sock; HRESULT hr;
- FIXME( "(%p,%ld,%p,%u) stub\n", + TRACE( "(%p,%ld,%p,%u)\n", data->lpMessage, data->dwMessageSize, data->lpISP, data->bReturnStatus );
- hr = IDirectPlaySP_GetSPData( data->lpISP, (void **)&dpwsData, &dpwsDataSize, DPSET_LOCAL ); + hr = IDirectPlaySP_GetSPData( data->lpISP, (void **) &dpwsData, &dpwsDataSize, DPSET_LOCAL ); if ( FAILED( hr ) ) return hr;
@@ -121,7 +126,42 @@ static HRESULT WINAPI DPWSCB_EnumSessions( LPDPSP_ENUMSESSIONSDATA data ) if ( FAILED (hr) ) return hr;
- return S_OK; + sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); + if ( sock == INVALID_SOCKET ) + { + ERR( "socket() failed\n" ); + return DPERR_UNAVAILABLE; + } + + if ( SOCKET_ERROR == setsockopt( sock, SOL_SOCKET, SO_BROADCAST, (const char *) &true, + sizeof( true ) ) ) + { + ERR( "setsockopt() failed\n" ); + closesocket( sock ); + return DPERR_UNAVAILABLE; + } + + memset( header, 0, sizeof( DPSP_MSG_HEADER ) ); + header->mixed = DPSP_MSG_MAKE_MIXED( data->dwMessageSize, DPSP_MSG_TOKEN_REMOTE ); + header->SockAddr.sin_family = AF_INET; + header->SockAddr.sin_port = dpwsData->tcpAddr.sin_port; + + memset( &addr, 0, sizeof( addr ) ); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl( INADDR_BROADCAST ); + addr.sin_port = htons( DPWS_PORT ); + + if ( SOCKET_ERROR == sendto( sock, data->lpMessage, data->dwMessageSize, 0, (SOCKADDR *) &addr, + sizeof( addr ) ) ) + { + ERR( "sendto() failed\n" ); + closesocket( sock ); + return DPERR_UNAVAILABLE; + } + + closesocket( sock ); + + return DP_OK; }
static HRESULT WINAPI DPWSCB_Reply( LPDPSP_REPLYDATA data )
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=148366
Your paranoid android.
=== w7u_2qxl (32 bit report) ===
dplayx: dplayx.c:0: Test failed: duplicate session {bdcfe03e-f0ec-415b-8211-6f86d8197fe1}.
=== w7u_el (32 bit report) ===
dplayx: dplayx.c:0: Test failed: duplicate session {bdcfe03e-f0ec-415b-8211-6f86d8197fe1}.
v3: - Rename `DPWS_StartServer()` and `DPWS_StopServer()` to `DPWS_Start()` and `DPWS_Stop()`.
This merge request was approved by Alistair Leslie-Hughes.