dpwsockx: Implementation of EnumSessions callback
[wine/gsoc_dplay.git] / dlls / dpwsockx / dpwsockx_main.c
bloba854a0aa5c399eb08fc044bf2281d3dd6eb3f78f
1 /* Internet TCP/IP and IPX Connection For DirectPlay
3 * Copyright 2008 Ismael Barros Barros
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "config.h"
22 #include <stdarg.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winsock2.h"
27 #include "dpwsockx_dll.h"
28 #include "wine/debug.h"
29 #include "dplay.h"
30 #include "wine/dplaysp.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(dplay);
36 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
38 TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
40 switch (fdwReason)
42 case DLL_WINE_PREATTACH:
43 return FALSE; /* prefer native version */
44 case DLL_PROCESS_ATTACH:
45 /* TODO: Initialization */
46 DisableThreadLibraryCalls(hinstDLL);
47 break;
48 case DLL_PROCESS_DETACH:
49 break;
50 default:
51 break;
54 return TRUE;
59 static DWORD WINAPI udp_listener_thread( LPVOID lpParameter )
61 LPDPWS_THREADDATA listener = lpParameter;
62 int recvMsgSize;
63 char buff[4096];
64 SOCKADDR_IN clientAddr;
65 int clientAddrSize;
67 listener->is_running = TRUE;
69 TRACE( "listening on port %d\n", ntohs(listener->addr.sin_port) );
71 for ( ;; )
73 clientAddrSize = sizeof(clientAddr);
75 /* Listen for messages */
76 recvMsgSize = recvfrom( listener->sock, buff, sizeof(buff), 0,
77 (LPSOCKADDR) &clientAddr, &clientAddrSize );
79 if ( recvMsgSize == 0 )
81 TRACE( "recvfrom(): connection closed\n" );
83 else if ( recvMsgSize == SOCKET_ERROR )
85 ERR( "recvfrom() failed: %d\n", WSAGetLastError() );
87 else
89 TRACE( "Handling message from %s:%d size %d\n",
90 inet_ntoa(clientAddr.sin_addr),
91 ntohs(clientAddr.sin_port),
92 recvMsgSize );
94 /* Copy client address to the header of the message, needed if
95 * we need to send a reply */
96 ((LPDPSP_MSG_HEADER) buff)->SockAddr.sin_addr = clientAddr.sin_addr;
98 /* Send messages to the upper layer */
99 IDirectPlaySP_HandleMessage( listener->lpISP,
100 buff + sizeof(DPSP_MSG_HEADER),
101 recvMsgSize - sizeof(DPSP_MSG_HEADER),
102 buff );
106 listener->is_running = FALSE;
107 return 0;
110 static DWORD WINAPI tcp_listener_thread( LPVOID lpParameter )
112 LPDPWS_THREADDATA listener = lpParameter;
113 int recvMsgSize;
114 char buff[4096];
115 SOCKADDR_IN clientAddr;
116 SOCKET clientSock;
117 int clientAddrSize;
118 int thread_return = 0;
120 listener->is_running = TRUE;
122 TRACE( "listening on port %d\n", ntohs(listener->addr.sin_port) );
124 for ( ;; )
126 clientAddrSize = sizeof(clientAddr);
128 /* Waiting for clients */
129 clientSock = accept( listener->sock, (LPSOCKADDR) &clientAddr,
130 &clientAddrSize );
131 if ( clientSock == INVALID_SOCKET )
133 ERR( "accept() failed: %d\n", WSAGetLastError() );
134 thread_return = 1;
135 goto end;
138 TRACE( "Handling client %s:%d\n",
139 inet_ntoa(clientAddr.sin_addr),
140 ntohs(clientAddr.sin_port) );
143 recvMsgSize = recv( clientSock, buff, sizeof(buff), 0 );
145 if ( recvMsgSize == 0 )
147 TRACE( "recv(): connection closed\n" );
149 else if ( recvMsgSize == SOCKET_ERROR )
151 ERR( "recv() failed: %d\n", WSAGetLastError() );
153 else
155 TRACE( "Handling message from %s:%d size %d\n",
156 inet_ntoa(clientAddr.sin_addr),
157 ntohs(clientAddr.sin_port),
158 recvMsgSize );
160 /* Copy client address to the header of the message, needed if
161 * we need to send a reply */
162 ((LPDPSP_MSG_HEADER) buff)->SockAddr.sin_addr = clientAddr.sin_addr;
164 /* Send messages to the upper layer */
165 IDirectPlaySP_HandleMessage( listener->lpISP,
166 buff + sizeof(DPSP_MSG_HEADER),
167 recvMsgSize - sizeof(DPSP_MSG_HEADER),
168 buff );
171 closesocket( clientSock );
174 end:
175 listener->is_running = FALSE;
176 return thread_return;
179 static HRESULT start_dplaysrv( LPDPWS_DATA dpwsData )
181 LPDPWS_THREADDATA listener = &dpwsData->dplaysrv;
182 int ret;
184 if ( listener->is_running )
186 TRACE( "Thread already started\n" );
187 return DP_OK;
190 listener->lpISP = dpwsData->lpISP;
192 /* Setting up a socket listening for UDP broadcasts on port 47624 */
193 /* TODO: With this implementation, if a second application tries to
194 * create a session on the same machine, it will fail.
195 * The native dplay approach is to run a program, dplaysvr.exe,
196 * that is actually who listens on this port. On time we should move
197 * to that kind of implementation. */
199 listener->sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
200 if ( listener->sock == INVALID_SOCKET )
202 ERR( "socket() failed: %d\n", WSAGetLastError() );
203 return DPERR_GENERIC;
206 memset( &listener->addr, 0, sizeof(SOCKADDR_IN) );
207 listener->addr.sin_family = AF_INET;
208 listener->addr.sin_addr.s_addr = htonl(INADDR_ANY);
209 listener->addr.sin_port = htons(DPWS_DPLAYSRV_PORT);
211 ret = bind( listener->sock, (LPSOCKADDR) &listener->addr,
212 sizeof(listener->addr) );
213 if ( ret == SOCKET_ERROR )
215 ERR( "bind() failed: %d\n", WSAGetLastError() );
216 return DPERR_GENERIC;
219 /* Launch thread */
220 listener->handle = CreateThread( NULL, 0, udp_listener_thread,
221 listener, 0, NULL );
222 return DP_OK;
225 static HRESULT start_listener( LPDPWS_DATA dpwsData, BOOL is_tcp )
227 LPDPWS_THREADDATA listener;
228 int port, ret;
230 listener = ( is_tcp
231 ? &dpwsData->tcp_listener
232 : &dpwsData->udp_listener );
234 if ( listener->is_running )
236 TRACE( "[%s] Thread already started\n", is_tcp ? "TCP" : "UDP" );
237 return DP_OK;
240 listener->lpISP = dpwsData->lpISP;
242 /* Setting up a socket listening for TCP or UDP connections
243 * on port 2300-2400 */
245 listener->sock = socket( AF_INET,
246 is_tcp ? SOCK_STREAM : SOCK_DGRAM,
247 is_tcp ? IPPROTO_TCP : IPPROTO_UDP );
248 if ( listener->sock == INVALID_SOCKET )
250 ERR( "[%s] socket() failed: %d\n",
251 is_tcp ? "TCP" : "UDP", WSAGetLastError() );
252 return DPERR_GENERIC;
255 memset( &listener->addr, 0, sizeof(SOCKADDR_IN) );
256 listener->addr.sin_family = AF_INET;
257 listener->addr.sin_addr.s_addr = htonl(INADDR_ANY);
259 /* Look for an available port */
260 port = DPWS_PORT_RANGE_START;
263 listener->addr.sin_port = htons(port);
264 ret = bind( listener->sock, (LPSOCKADDR) &listener->addr,
265 sizeof(listener->addr) );
267 while ( ( ret == SOCKET_ERROR ) &&
268 ( WSAGetLastError() == WSAEADDRINUSE ) &&
269 ( ++port <= DPWS_PORT_RANGE_END ) );
271 if ( ret == SOCKET_ERROR )
273 ERR( "[%s] bind() failed: %d\n",
274 is_tcp ? "TCP" : "UDP", WSAGetLastError() );
275 return DPERR_GENERIC;
278 TRACE( "[%s] found available port %d\n", is_tcp ? "TCP" : "UDP", port );
280 if ( is_tcp )
282 ret = listen( listener->sock, SOMAXCONN );
283 if ( ret == SOCKET_ERROR )
285 ERR( "[%s] listen() failed: %d\n",
286 is_tcp ? "TCP" : "UDP", WSAGetLastError() );
287 return DPERR_GENERIC;
291 /* Launch thread */
292 listener->handle = CreateThread( NULL, 0,
293 ( is_tcp
294 ? tcp_listener_thread
295 : udp_listener_thread ),
296 listener, 0, NULL );
297 return DP_OK;
301 static HRESULT send_udp_message( LPVOID message,
302 DWORD messageSize,
303 LPSOCKADDR destAddr )
305 SOCKET sock;
306 int ret;
308 TRACE( "Sending message to %s:%d\n",
309 inet_ntoa(((LPSOCKADDR_IN) destAddr)->sin_addr),
310 ntohs(((LPSOCKADDR_IN) destAddr)->sin_port) );
312 if ( messageSize > DPWS_MAXBUFFERSIZE )
314 return DPERR_SENDTOOBIG;
317 sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
318 if ( sock == INVALID_SOCKET )
320 ERR( "socket() failed: %d\n", WSAGetLastError() );
321 return DPERR_GENERIC;
324 if ( ((LPSOCKADDR_IN)destAddr)->sin_addr.s_addr == htonl(INADDR_BROADCAST) )
326 /* Allow the socket to send broadcast messages */
327 BOOL allowBroadcast = TRUE;
328 ret = setsockopt( sock, SOL_SOCKET, SO_BROADCAST,
329 (char*) &allowBroadcast, sizeof(BOOL) );
330 if ( ret == SOCKET_ERROR )
332 ERR( "setsockopt() failed: %d\n", WSAGetLastError() );
333 return DPERR_GENERIC;
337 /* Send message */
338 ret = sendto( sock, message, messageSize, 0, destAddr, sizeof(SOCKADDR) );
339 if ( ret == SOCKET_ERROR )
341 ERR( "sendto() failed: %d\n", WSAGetLastError() );
342 return DPERR_GENERIC;
344 else if ( ret != messageSize )
346 ERR( "%d/%d bytes sent", ret, messageSize );
347 return DPERR_GENERIC;
350 return DP_OK;
353 static HRESULT send_tcp_message( LPVOID message,
354 DWORD messageSize,
355 LPSOCKADDR destAddr )
357 SOCKET sock;
358 int ret;
360 /* TODO:
361 * For each message sent, we open a TCP socket, send the message and
362 * close the socket. The desired behaviour would be to open a socket
363 * only if there's no socket for the requesting address, and keep
364 * sending messages with that socket, without closing it. */
366 TRACE( "Sending message to %s:%d\n",
367 inet_ntoa(((LPSOCKADDR_IN) destAddr)->sin_addr),
368 ntohs(((LPSOCKADDR_IN) destAddr)->sin_port) );
370 if ( messageSize > DPWS_GUARANTEED_MAXBUFFERSIZE )
372 return DPERR_SENDTOOBIG;
375 sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
376 if ( sock == INVALID_SOCKET )
378 ERR( "socket() failed: %d\n", WSAGetLastError() );
379 return DPERR_GENERIC;
382 ret = connect( sock, destAddr, sizeof(SOCKADDR) );
383 if ( ret == SOCKET_ERROR )
385 if ( WSAGetLastError() != WSAEISCONN )
387 ERR( "connect() failed: %d\n", WSAGetLastError() );
388 return DPERR_GENERIC;
392 ret = send( sock, message, messageSize, 0 );
393 if ( ret == SOCKET_ERROR )
395 ERR( "send() failed: %d\n", WSAGetLastError() );
396 return DPERR_GENERIC;
398 else if ( ret != messageSize )
400 ERR( "%d/%d bytes sent", ret, messageSize );
401 return DPERR_GENERIC;
404 ret = closesocket( sock );
405 if ( ret == SOCKET_ERROR)
407 ERR( "closesocket() failed %d\n", WSAGetLastError() );
408 return DPERR_GENERIC;
411 return DP_OK;
415 static HRESULT WINAPI DPWSCB_EnumSessions( LPDPSP_ENUMSESSIONSDATA data )
417 LPDPWS_DATA dpwsData;
418 DWORD dwDataSize;
419 SOCKADDR_IN destAddr;
421 TRACE( "(%p,%d,%p,%u)\n",
422 data->lpMessage, data->dwMessageSize,
423 data->lpISP, data->bReturnStatus );
425 IDirectPlaySP_GetSPData( data->lpISP, (LPVOID*) &dpwsData, &dwDataSize,
426 DPGET_LOCAL );
428 /* Start listener to get replies if it's not started yet.
429 * This needs to be done before we build the local address,
430 * otherwise we won't know in which port we're listening. */
431 if ( !dpwsData->tcp_listener.is_running )
433 HRESULT hr = start_listener( dpwsData, TRUE );
434 if ( FAILED(hr) )
436 return hr;
440 /* Destination address */
441 /* TODO: Instead of getting always the broadcast address,
442 * we should throw a popup message asking for an address,
443 * and only broadcast if no address is provided. */
444 memset( &destAddr, 0, sizeof(SOCKADDR_IN) );
445 destAddr.sin_family = AF_INET;
446 destAddr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
447 destAddr.sin_port = htons(DPWS_DPLAYSRV_PORT);
449 /* Add header to message body */
450 ((LPDPSP_MSG_HEADER) data->lpMessage)->size
451 = data->dwMessageSize | DPSP_MSG_TOKEN_REMOTE;
452 ((LPDPSP_MSG_HEADER) data->lpMessage)->SockAddr
453 = dpwsData->tcp_listener.addr;
455 return send_udp_message( data->lpMessage, data->dwMessageSize,
456 (LPSOCKADDR) &destAddr );
459 static HRESULT WINAPI DPWSCB_Reply( LPDPSP_REPLYDATA data )
461 LPDPWS_DATA dpwsData;
462 DWORD dwDataSize;
463 SOCKADDR_IN destAddr;
465 TRACE( "(%p,%p,%d,%d,%p)\n",
466 data->lpSPMessageHeader, data->lpMessage, data->dwMessageSize,
467 data->idNameServer, data->lpISP );
469 IDirectPlaySP_GetSPData( data->lpISP, (LPVOID*) &dpwsData, &dwDataSize,
470 DPGET_LOCAL );
472 /* Extract destination address from request header */
473 destAddr = ((LPDPSP_MSG_HEADER) data->lpSPMessageHeader)->SockAddr;
475 /* Add header to message body */
476 ((LPDPSP_MSG_HEADER) data->lpMessage)->size
477 = data->dwMessageSize | DPSP_MSG_TOKEN_REMOTE;
478 ((LPDPSP_MSG_HEADER) data->lpMessage)->SockAddr
479 = dpwsData->tcp_listener.addr;
481 return send_tcp_message( data->lpMessage, data->dwMessageSize,
482 (LPSOCKADDR) &destAddr );
485 static HRESULT WINAPI DPWSCB_Send( LPDPSP_SENDDATA data )
487 LPDPWS_DATA dpwsData;
488 LPDPWS_PLAYER_DATA dpwsPlayerData;
489 DWORD dwDataSize, dwPlayerDataSize;
490 SOCKADDR_IN destAddr;
492 TRACE( "(0x%08x,0x%08x,0x%08x,%p,%d,%u,%p)\n",
493 data->dwFlags, data->idPlayerTo, data->idPlayerFrom,
494 data->lpMessage, data->dwMessageSize,
495 data->bSystemMessage, data->lpISP );
497 IDirectPlaySP_GetSPData( data->lpISP, (LPVOID*) &dpwsData, &dwDataSize,
498 DPGET_LOCAL );
500 /* Get destination address from the player id */
501 if ( data->idPlayerTo == 0 ) /* Message to nameserver */
503 destAddr = dpwsData->nameserverAddr;
505 else
507 HRESULT hr;
508 hr = IDirectPlaySP_GetSPPlayerData( data->lpISP, data->idPlayerTo,
509 (LPVOID*) &dpwsPlayerData,
510 &dwPlayerDataSize, DPGET_REMOTE );
511 if ( FAILED(hr) )
513 return hr;
516 if ( ( data->bSystemMessage ) ||
517 ( data->dwFlags & DPSEND_GUARANTEED ) )
519 destAddr = dpwsPlayerData->tcpAddr;
521 else
523 destAddr = dpwsPlayerData->udpAddr;
527 /* Add header to message body */
528 ((LPDPSP_MSG_HEADER) data->lpMessage)->size
529 = data->dwMessageSize | DPSP_MSG_TOKEN_REMOTE;
530 ((LPDPSP_MSG_HEADER) data->lpMessage)->SockAddr
531 = dpwsData->tcp_listener.addr;
533 /* If the flag DPSESSION_DIRECTPLAYPROTOCOL is set we are
534 * supposed to send UDP messages and implement all the TCP
535 * functionality ourselves in dplayx, but for now let's not
536 * reinvent the wheel. */
537 if ( ( data->bSystemMessage ) ||
538 ( data->dwFlags & DPSEND_GUARANTEED ) )
540 return send_tcp_message( data->lpMessage, data->dwMessageSize,
541 (LPSOCKADDR) &destAddr );
543 else
545 return send_udp_message( data->lpMessage, data->dwMessageSize,
546 (LPSOCKADDR) &destAddr );
550 static HRESULT WINAPI DPWSCB_CreatePlayer( LPDPSP_CREATEPLAYERDATA data )
552 FIXME( "(%d,0x%08x,%p,%p) stub\n",
553 data->idPlayer, data->dwFlags,
554 data->lpSPMessageHeader, data->lpISP );
555 return DPERR_UNSUPPORTED;
558 static HRESULT WINAPI DPWSCB_DeletePlayer( LPDPSP_DELETEPLAYERDATA data )
560 FIXME( "(%d,0x%08x,%p) stub\n",
561 data->idPlayer, data->dwFlags, data->lpISP );
562 return DPERR_UNSUPPORTED;
565 static HRESULT WINAPI DPWSCB_GetAddress( LPDPSP_GETADDRESSDATA data )
567 FIXME( "(%d,0x%08x,%p,%p,%p) stub\n",
568 data->idPlayer, data->dwFlags, data->lpAddress,
569 data->lpdwAddressSize, data->lpISP );
570 return DPERR_UNSUPPORTED;
573 static HRESULT WINAPI DPWSCB_GetCaps( LPDPSP_GETCAPSDATA data )
575 TRACE( "(%d,%p,0x%08x,%p)\n",
576 data->idPlayer, data->lpCaps, data->dwFlags, data->lpISP );
578 data->lpCaps->dwFlags = ( DPCAPS_ASYNCSUPPORTED |
579 DPCAPS_GUARANTEEDOPTIMIZED |
580 DPCAPS_GUARANTEEDSUPPORTED );
582 data->lpCaps->dwMaxQueueSize = DPWS_MAXQUEUESIZE;
583 data->lpCaps->dwHundredBaud = DPWS_HUNDREDBAUD;
584 data->lpCaps->dwLatency = DPWS_LATENCY;
585 data->lpCaps->dwMaxLocalPlayers = DPWS_MAXLOCALPLAYERS;
586 data->lpCaps->dwHeaderLength = sizeof(DPSP_MSG_HEADER);
587 data->lpCaps->dwTimeout = DPWS_TIMEOUT;
589 if ( data->dwFlags & DPGETCAPS_GUARANTEED )
591 data->lpCaps->dwMaxBufferSize = DPWS_GUARANTEED_MAXBUFFERSIZE;
592 data->lpCaps->dwMaxPlayers = DPWS_GUARANTEED_MAXPLAYERS;
594 else
596 data->lpCaps->dwMaxBufferSize = DPWS_MAXBUFFERSIZE;
597 data->lpCaps->dwMaxPlayers = DPWS_MAXPLAYERS;
600 /* Substract size of service provider header */
601 data->lpCaps->dwMaxBufferSize -= sizeof(DPSP_MSG_HEADER);
602 return DP_OK;
605 static HRESULT WINAPI DPWSCB_Open( LPDPSP_OPENDATA data )
607 LPDPWS_DATA dpwsData;
608 DWORD dwDataSize;
609 HRESULT hr;
611 TRACE( "(%u,%p,%p,%u,0x%08x,0x%08x)\n",
612 data->bCreate, data->lpSPMessageHeader, data->lpISP,
613 data->bReturnStatus, data->dwOpenFlags, data->dwSessionFlags );
615 IDirectPlaySP_GetSPData( data->lpISP, (LPVOID*) &dpwsData, &dwDataSize,
616 DPGET_LOCAL );
618 if ( data->bCreate )
620 hr = start_dplaysrv( dpwsData );
621 if ( FAILED(hr) )
623 return hr;
626 hr = start_listener( dpwsData, TRUE );
627 if ( FAILED(hr) )
629 return hr;
632 else
634 /* Save address of name server */
635 dpwsData->nameserverAddr =
636 ((LPDPSP_MSG_HEADER) data->lpSPMessageHeader)->SockAddr;
639 /* TCP listener was already started in EnumConnections */
641 hr = start_listener( dpwsData, FALSE );
642 if ( FAILED(hr) )
644 return hr;
647 return DP_OK;
650 static HRESULT WINAPI DPWSCB_CloseEx( LPDPSP_CLOSEDATA data )
652 FIXME( "(%p) stub\n", data->lpISP );
653 return DPERR_UNSUPPORTED;
656 static HRESULT WINAPI DPWSCB_ShutdownEx( LPDPSP_SHUTDOWNDATA data )
658 FIXME( "(%p) stub\n", data->lpISP );
659 return DPERR_UNSUPPORTED;
662 static HRESULT WINAPI DPWSCB_GetAddressChoices( LPDPSP_GETADDRESSCHOICESDATA data )
664 FIXME( "(%p,%p,%p) stub\n",
665 data->lpAddress, data->lpdwAddressSize, data->lpISP );
666 return DPERR_UNSUPPORTED;
669 static HRESULT WINAPI DPWSCB_SendEx( LPDPSP_SENDEXDATA data )
671 FIXME( "(%p,0x%08x,%d,%d,%p,%d,%d,%d,%d,%p,%p,%u) stub\n",
672 data->lpISP, data->dwFlags, data->idPlayerTo, data->idPlayerFrom,
673 data->lpSendBuffers, data->cBuffers, data->dwMessageSize,
674 data->dwPriority, data->dwTimeout, data->lpDPContext,
675 data->lpdwSPMsgID, data->bSystemMessage );
676 return DPERR_UNSUPPORTED;
679 static HRESULT WINAPI DPWSCB_SendToGroupEx( LPDPSP_SENDTOGROUPEXDATA data )
681 FIXME( "(%p,0x%08x,%d,%d,%p,%d,%d,%d,%d,%p,%p) stub\n",
682 data->lpISP, data->dwFlags, data->idGroupTo, data->idPlayerFrom,
683 data->lpSendBuffers, data->cBuffers, data->dwMessageSize,
684 data->dwPriority, data->dwTimeout, data->lpDPContext,
685 data->lpdwSPMsgID );
686 return DPERR_UNSUPPORTED;
689 static HRESULT WINAPI DPWSCB_Cancel( LPDPSP_CANCELDATA data )
691 FIXME( "(%p,0x%08x,%p,%d,0x%08x,0x%08x) stub\n",
692 data->lpISP, data->dwFlags, data->lprglpvSPMsgID, data->cSPMsgID,
693 data->dwMinPriority, data->dwMaxPriority );
694 return DPERR_UNSUPPORTED;
697 static HRESULT WINAPI DPWSCB_GetMessageQueue( LPDPSP_GETMESSAGEQUEUEDATA data )
699 FIXME( "(%p,0x%08x,%d,%d,%p,%p) stub\n",
700 data->lpISP, data->dwFlags, data->idFrom, data->idTo,
701 data->lpdwNumMsgs, data->lpdwNumBytes );
702 return DPERR_UNSUPPORTED;
705 static void setup_callbacks( LPDPSP_SPCALLBACKS lpCB )
707 lpCB->EnumSessions = DPWSCB_EnumSessions;
708 lpCB->Reply = DPWSCB_Reply;
709 lpCB->Send = DPWSCB_Send;
710 lpCB->CreatePlayer = DPWSCB_CreatePlayer;
711 lpCB->DeletePlayer = DPWSCB_DeletePlayer;
712 lpCB->GetAddress = DPWSCB_GetAddress;
713 lpCB->GetCaps = DPWSCB_GetCaps;
714 lpCB->Open = DPWSCB_Open;
715 lpCB->CloseEx = DPWSCB_CloseEx;
716 lpCB->ShutdownEx = DPWSCB_ShutdownEx;
717 lpCB->GetAddressChoices = DPWSCB_GetAddressChoices;
718 lpCB->SendEx = DPWSCB_SendEx;
719 lpCB->SendToGroupEx = DPWSCB_SendToGroupEx;
720 lpCB->Cancel = DPWSCB_Cancel;
721 lpCB->GetMessageQueue = DPWSCB_GetMessageQueue;
723 lpCB->AddPlayerToGroup = NULL;
724 lpCB->Close = NULL;
725 lpCB->CreateGroup = NULL;
726 lpCB->DeleteGroup = NULL;
727 lpCB->RemovePlayerFromGroup = NULL;
728 lpCB->SendToGroup = NULL;
729 lpCB->Shutdown = NULL;
733 /******************************************************************
734 * SPInit (DPWSOCKX.1)
736 HRESULT WINAPI SPInit( LPSPINITDATA lpspData )
738 WSADATA wsaData;
739 DPWS_DATA dpwsData;
741 TRACE( "Initializing library for %s (%s)\n",
742 wine_dbgstr_guid(lpspData->lpGuid), debugstr_w(lpspData->lpszName) );
744 /* We only support TCP/IP service */
745 if ( !IsEqualGUID(lpspData->lpGuid, &DPSPGUID_TCPIP) )
747 return DPERR_UNAVAILABLE;
750 /* Assign callback functions */
751 setup_callbacks( lpspData->lpCB );
753 /* Load Winsock 2.0 DLL */
754 if ( WSAStartup( MAKEWORD(2, 0), &wsaData ) != 0 )
756 ERR( "WSAStartup() failed\n" );
757 return DPERR_UNAVAILABLE;
760 /* Initialize internal data */
761 memset( &dpwsData, 0, sizeof(DPWS_DATA) );
762 dpwsData.lpISP = lpspData->lpISP;
763 IDirectPlaySP_SetSPData( lpspData->lpISP, &dpwsData, sizeof(DPWS_DATA),
764 DPSET_LOCAL );
766 /* dplay needs to know the size of the header */
767 lpspData->dwSPHeaderSize = sizeof(DPSP_MSG_HEADER);
769 return DP_OK;