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
27 #include "dpwsockx_dll.h"
28 #include "wine/debug.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
);
42 case DLL_WINE_PREATTACH
:
43 return FALSE
; /* prefer native version */
44 case DLL_PROCESS_ATTACH
:
45 /* TODO: Initialization */
46 DisableThreadLibraryCalls(hinstDLL
);
48 case DLL_PROCESS_DETACH
:
59 static DWORD WINAPI
udp_listener_thread( LPVOID lpParameter
)
61 LPDPWS_THREADDATA listener
= lpParameter
;
64 SOCKADDR_IN clientAddr
;
67 listener
->is_running
= TRUE
;
69 TRACE( "listening on port %d\n", ntohs(listener
->addr
.sin_port
) );
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() );
89 TRACE( "Handling message from %s:%d size %d\n",
90 inet_ntoa(clientAddr
.sin_addr
),
91 ntohs(clientAddr
.sin_port
),
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
),
106 listener
->is_running
= FALSE
;
110 static DWORD WINAPI
tcp_listener_thread( LPVOID lpParameter
)
112 LPDPWS_THREADDATA listener
= lpParameter
;
115 SOCKADDR_IN clientAddr
;
118 int thread_return
= 0;
120 listener
->is_running
= TRUE
;
122 TRACE( "listening on port %d\n", ntohs(listener
->addr
.sin_port
) );
126 clientAddrSize
= sizeof(clientAddr
);
128 /* Waiting for clients */
129 clientSock
= accept( listener
->sock
, (LPSOCKADDR
) &clientAddr
,
131 if ( clientSock
== INVALID_SOCKET
)
133 ERR( "accept() failed: %d\n", WSAGetLastError() );
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() );
155 TRACE( "Handling message from %s:%d size %d\n",
156 inet_ntoa(clientAddr
.sin_addr
),
157 ntohs(clientAddr
.sin_port
),
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
),
171 closesocket( clientSock
);
175 listener
->is_running
= FALSE
;
176 return thread_return
;
179 static HRESULT
start_dplaysrv( LPDPWS_DATA dpwsData
)
181 LPDPWS_THREADDATA listener
= &dpwsData
->dplaysrv
;
184 if ( listener
->is_running
)
186 TRACE( "Thread already started\n" );
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
;
220 listener
->handle
= CreateThread( NULL
, 0, udp_listener_thread
,
225 static HRESULT
start_listener( LPDPWS_DATA dpwsData
, BOOL is_tcp
)
227 LPDPWS_THREADDATA listener
;
231 ? &dpwsData
->tcp_listener
232 : &dpwsData
->udp_listener
);
234 if ( listener
->is_running
)
236 TRACE( "[%s] Thread already started\n", is_tcp
? "TCP" : "UDP" );
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
);
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
;
292 listener
->handle
= CreateThread( NULL
, 0,
294 ? tcp_listener_thread
295 : udp_listener_thread
),
301 static HRESULT
send_udp_message( LPVOID message
,
303 LPSOCKADDR destAddr
)
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
;
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
;
353 static HRESULT
send_tcp_message( LPVOID message
,
355 LPSOCKADDR destAddr
)
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
;
415 static HRESULT WINAPI
DPWSCB_EnumSessions( LPDPSP_ENUMSESSIONSDATA data
)
417 LPDPWS_DATA dpwsData
;
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
,
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
);
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
;
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
,
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
,
500 /* Get destination address from the player id */
501 if ( data
->idPlayerTo
== 0 ) /* Message to nameserver */
503 destAddr
= dpwsData
->nameserverAddr
;
508 hr
= IDirectPlaySP_GetSPPlayerData( data
->lpISP
, data
->idPlayerTo
,
509 (LPVOID
*) &dpwsPlayerData
,
510 &dwPlayerDataSize
, DPGET_REMOTE
);
516 if ( ( data
->bSystemMessage
) ||
517 ( data
->dwFlags
& DPSEND_GUARANTEED
) )
519 destAddr
= dpwsPlayerData
->tcpAddr
;
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
);
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
;
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
);
605 static HRESULT WINAPI
DPWSCB_Open( LPDPSP_OPENDATA data
)
607 LPDPWS_DATA dpwsData
;
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
,
620 hr
= start_dplaysrv( dpwsData
);
626 hr
= start_listener( dpwsData
, TRUE
);
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
);
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
,
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
;
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
)
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
),
766 /* dplay needs to know the size of the header */
767 lpspData
->dwSPHeaderSize
= sizeof(DPSP_MSG_HEADER
);