[PATCH 2/2] dpwsockx: Implementation of Open callback

Ismael Barros razielmine at gmail.com
Sun Sep 13 14:58:48 CDT 2009


---
 dlls/dpwsockx/dpwsockx_main.c |  284 ++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 282 insertions(+), 2 deletions(-)

diff --git a/dlls/dpwsockx/dpwsockx_main.c b/dlls/dpwsockx/dpwsockx_main.c
index f4e571c..8b427bd 100644
--- a/dlls/dpwsockx/dpwsockx_main.c
+++ b/dlls/dpwsockx/dpwsockx_main.c
@@ -54,6 +54,249 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
 }
 
 
+
+static DWORD WINAPI udp_listener_thread( LPVOID lpParameter )
+{
+    LPDPWS_THREADDATA listener = lpParameter;
+    int recvMsgSize;
+    char buff[4096];
+    SOCKADDR_IN clientAddr;
+    int clientAddrSize;
+
+    listener->is_running = TRUE;
+
+    TRACE( "listening on port %d\n", ntohs(listener->addr.sin_port) );
+
+    for ( ;; )
+    {
+        clientAddrSize = sizeof(clientAddr);
+
+        /* Listen for messages */
+        recvMsgSize = recvfrom( listener->sock, buff, sizeof(buff), 0,
+                                (LPSOCKADDR) &clientAddr, &clientAddrSize );
+
+        if ( recvMsgSize == 0 )
+        {
+            TRACE( "recvfrom(): connection closed\n" );
+        }
+        else if ( recvMsgSize == SOCKET_ERROR )
+        {
+            ERR( "recvfrom() failed: %d\n", WSAGetLastError() );
+        }
+        else
+        {
+            TRACE( "Handling message from %s:%d size %d\n",
+                   inet_ntoa(clientAddr.sin_addr),
+                   ntohs(clientAddr.sin_port),
+                   recvMsgSize );
+
+            /* Copy client address to the header of the message, needed if
+             * we need to send a reply */
+            ((LPDPSP_MSG_HEADER) buff)->SockAddr.sin_addr = clientAddr.sin_addr;
+
+            /* Send messages to the upper layer */
+            IDirectPlaySP_HandleMessage( listener->lpISP,
+                                         buff + sizeof(DPSP_MSG_HEADER),
+                                         recvMsgSize - sizeof(DPSP_MSG_HEADER),
+                                         buff );
+        }
+    }
+
+    listener->is_running = FALSE;
+    return 0;
+}
+
+static DWORD WINAPI tcp_listener_thread( LPVOID lpParameter )
+{
+    LPDPWS_THREADDATA listener = lpParameter;
+    int recvMsgSize;
+    char buff[4096];
+    SOCKADDR_IN clientAddr;
+    SOCKET clientSock;
+    int clientAddrSize;
+    int thread_return = 0;
+
+    listener->is_running = TRUE;
+
+    TRACE( "listening on port %d\n", ntohs(listener->addr.sin_port) );
+
+    for ( ;; )
+    {
+        clientAddrSize = sizeof(clientAddr);
+
+        /* Waiting for clients */
+        clientSock = accept( listener->sock, (LPSOCKADDR) &clientAddr,
+                             &clientAddrSize );
+        if ( clientSock == INVALID_SOCKET )
+        {
+            ERR( "accept() failed: %d\n", WSAGetLastError() );
+            thread_return = 1;
+            goto end;
+        }
+
+        TRACE( "Handling client %s:%d\n",
+               inet_ntoa(clientAddr.sin_addr),
+               ntohs(clientAddr.sin_port) );
+
+
+        recvMsgSize = recv( clientSock, buff, sizeof(buff), 0 );
+
+        if ( recvMsgSize == 0 )
+        {
+            TRACE( "recv(): connection closed\n" );
+        }
+        else if ( recvMsgSize == SOCKET_ERROR )
+        {
+            ERR( "recv() failed: %d\n", WSAGetLastError() );
+        }
+        else
+        {
+            TRACE( "Handling message from %s:%d size %d\n",
+                   inet_ntoa(clientAddr.sin_addr),
+                   ntohs(clientAddr.sin_port),
+                   recvMsgSize );
+
+            /* Copy client address to the header of the message, needed if
+             * we need to send a reply */
+            ((LPDPSP_MSG_HEADER) buff)->SockAddr.sin_addr = clientAddr.sin_addr;
+
+            /* Send messages to the upper layer */
+            IDirectPlaySP_HandleMessage( listener->lpISP,
+                                         buff + sizeof(DPSP_MSG_HEADER),
+                                         recvMsgSize - sizeof(DPSP_MSG_HEADER),
+                                         buff );
+        }
+
+        closesocket( clientSock );
+    }
+
+end:
+    listener->is_running = FALSE;
+    return thread_return;
+}
+
+static HRESULT start_dplaysrv( LPDPWS_DATA dpwsData )
+{
+    LPDPWS_THREADDATA listener = &dpwsData->dplaysrv;
+    int ret;
+
+    if ( listener->is_running )
+    {
+        TRACE( "Thread already started\n" );
+        return DP_OK;
+    }
+
+    listener->lpISP = dpwsData->lpISP;
+
+    /* Setting up a socket listening for UDP broadcasts on port 47624 */
+    /* TODO: With this implementation, if a second application tries to
+     * create a session on the same machine, it will fail.
+     * The native dplay approach is to run a program, dplaysvr.exe,
+     * that is actually who listens on this port. On time we should move
+     * to that kind of implementation. */
+
+    listener->sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
+    if ( listener->sock == INVALID_SOCKET )
+    {
+        ERR( "socket() failed: %d\n", WSAGetLastError() );
+        return DPERR_GENERIC;
+    }
+
+    memset( &listener->addr, 0, sizeof(SOCKADDR_IN) );
+    listener->addr.sin_family = AF_INET;
+    listener->addr.sin_addr.s_addr = htonl(INADDR_ANY);
+    listener->addr.sin_port = htons(DPWS_DPLAYSRV_PORT);
+
+    ret = bind( listener->sock, (LPSOCKADDR) &listener->addr,
+                sizeof(listener->addr) );
+    if ( ret == SOCKET_ERROR )
+    {
+        ERR( "bind() failed: %d\n", WSAGetLastError() );
+        return DPERR_GENERIC;
+    }
+
+    /* Launch thread */
+    listener->handle = CreateThread( NULL, 0, udp_listener_thread,
+                                     listener, 0, NULL );
+    return DP_OK;
+}
+
+static HRESULT start_listener( LPDPWS_DATA dpwsData, BOOL is_tcp )
+{
+    LPDPWS_THREADDATA listener;
+    int port, ret;
+
+    listener = ( is_tcp
+                 ? &dpwsData->tcp_listener
+                 : &dpwsData->udp_listener );
+
+    if ( listener->is_running )
+    {
+        TRACE( "[%s] Thread already started\n", is_tcp ? "TCP" : "UDP" );
+        return DP_OK;
+    }
+
+    listener->lpISP = dpwsData->lpISP;
+
+    /* Setting up a socket listening for TCP or UDP connections
+     * on port 2300-2400 */
+
+    listener->sock = socket( AF_INET,
+                             is_tcp ? SOCK_STREAM : SOCK_DGRAM,
+                             is_tcp ? IPPROTO_TCP : IPPROTO_UDP );
+    if ( listener->sock == INVALID_SOCKET )
+    {
+        ERR( "[%s] socket() failed: %d\n",
+             is_tcp ? "TCP" : "UDP", WSAGetLastError() );
+        return DPERR_GENERIC;
+    }
+
+    memset( &listener->addr, 0, sizeof(SOCKADDR_IN) );
+    listener->addr.sin_family = AF_INET;
+    listener->addr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+    /* Look for an available port */
+    port = DPWS_PORT_RANGE_START;
+    do
+    {
+        listener->addr.sin_port = htons(port);
+        ret = bind( listener->sock, (LPSOCKADDR) &listener->addr,
+                    sizeof(listener->addr) );
+    }
+    while ( ( ret == SOCKET_ERROR ) &&
+            ( WSAGetLastError() == WSAEADDRINUSE ) &&
+            ( ++port <= DPWS_PORT_RANGE_END ) );
+
+    if ( ret == SOCKET_ERROR )
+    {
+        ERR( "[%s] bind() failed: %d\n",
+             is_tcp ? "TCP" : "UDP",  WSAGetLastError() );
+        return DPERR_GENERIC;
+    }
+
+    TRACE( "[%s] found available port %d\n", is_tcp ? "TCP" : "UDP", port );
+
+    if ( is_tcp )
+    {
+        ret = listen( listener->sock, SOMAXCONN );
+        if ( ret == SOCKET_ERROR )
+        {
+            ERR( "[%s] listen() failed: %d\n",
+                 is_tcp ? "TCP" : "UDP", WSAGetLastError() );
+            return DPERR_GENERIC;
+        }
+    }
+
+    /* Launch thread */
+    listener->handle = CreateThread( NULL, 0,
+                                     ( is_tcp
+                                       ? tcp_listener_thread
+                                       : udp_listener_thread ),
+                                     listener, 0, NULL );
+    return DP_OK;
+}
+
+
 static HRESULT WINAPI DPWSCB_EnumSessions( LPDPSP_ENUMSESSIONSDATA data )
 {
     FIXME( "(%p,%d,%p,%u) stub\n",
@@ -136,10 +379,47 @@ static HRESULT WINAPI DPWSCB_GetCaps( LPDPSP_GETCAPSDATA data )
 
 static HRESULT WINAPI DPWSCB_Open( LPDPSP_OPENDATA data )
 {
-    FIXME( "(%u,%p,%p,%u,0x%08x,0x%08x) stub\n",
+    LPDPWS_DATA dpwsData;
+    DWORD dwDataSize;
+    HRESULT hr;
+
+    TRACE( "(%u,%p,%p,%u,0x%08x,0x%08x)\n",
            data->bCreate, data->lpSPMessageHeader, data->lpISP,
            data->bReturnStatus, data->dwOpenFlags, data->dwSessionFlags );
-    return DPERR_UNSUPPORTED;
+
+    IDirectPlaySP_GetSPData( data->lpISP, (LPVOID*) &dpwsData, &dwDataSize,
+                             DPGET_LOCAL );
+
+    if ( data->bCreate )
+    {
+        hr = start_dplaysrv( dpwsData );
+        if ( FAILED(hr) )
+        {
+            return hr;
+        }
+
+        hr = start_listener( dpwsData, TRUE );
+        if ( FAILED(hr) )
+        {
+            return hr;
+        }
+    }
+    else
+    {
+        /* Save address of name server */
+        dpwsData->nameserverAddr =
+            ((LPDPSP_MSG_HEADER) data->lpSPMessageHeader)->SockAddr;
+    }
+
+    /* TCP listener was already started in EnumConnections */
+
+    hr = start_listener( dpwsData, FALSE );
+    if ( FAILED(hr) )
+    {
+        return hr;
+    }
+
+    return DP_OK;
 }
 
 static HRESULT WINAPI DPWSCB_CloseEx( LPDPSP_CLOSEDATA data )
-- 
1.6.4.2




More information about the wine-patches mailing list