/*==========================================================================;
 *
 *  Copyright (C) 1994-1995 Microsoft Corporation.  All Rights Reserved.
 *
 *  File:       dplayi.h
 *  Content:    DirectPlay data structures
 *  History:
 *   Date               By      Reason
 *   ====               ==      ======
 *      1/96            andyco  created it
 *  1/26/96             andyco  list data structures
 *      4/10/96         andyco  removed dpmess.h
 *      4/23/96         andyco  added ipx support
 *      4/25/96         andyco  messages now have blobs (sockaddr's) instead of dwReserveds  
 *      8/10/96         kipo    update max message size to be (2^20) - 1
 *      8/15/96         andyco  added local data
 *      8/30/96         andyco  clean it up b4 you shut it down! added globaldata.
 *      9/3/96          andyco  bagosockets
 *      12/18/96        andyco  de-threading - use a fixed # of prealloced threads.
 *                                              cruised the enum socket / thread - use the system
 *                                              socket / thread instead. updated global struct.
 *      2/7/97          andyco  moved all per IDirectPlay globals into globaldata
 *      3/17/97         kipo    GetServerAddress() now returns an error so that we can
 *                                              return DPERR_USERCANCEL from the EnumSessions dialog
 *      3/25/97         andyco  dec debug lock counter b4 dropping lock! 
 *      4/11/97         andyco  added saddrControlSocket
 *      5/12/97         kipo    added ADDR_BUFFER_SIZE constant and removed unused variables
 *      5/15/97         andyco  added ipx spare thread to global data - used when nameserver 
 *                                              migrates to this host to make sure that old system receive 
 *                                              thread shuts down 
 *      6/22/97         kipo    include wsnwlink.h
 *      7/11/97         andyco  added support for ws2 + async reply thread
 *      8/25/97         sohailm added DEFAULT_RECEIVE_BUFFERSIZE
 *      12/5/97         andyco  voice support
 *      01/5/97         sohailm added fd big set related definitions and macros (#15244).
 *      1/20/98         myronth #ifdef'd out voice support
 *      1/27/98         sohailm added firewall support
 *  2/13/98     aarono  added async support
 *      2/18/98    a-peterz Comment byte order mess-up with SERVER_xxx_PORT constants
 *  3/3/98      aarono  Bug#19188 remove accept thread 
 *  12/15/98    aarono  make async enum run async
 **************************************************************************/

#ifndef __DPSP_INCLUDED__
#define __DPSP_INCLUDED__
#include "windows.h"
#include "windowsx.h"
#include "wsipx.h"
#include "wsnwlink.h"
#include "dplaysp.h"
#include "bilink.h"
#include "fpm.h"

#ifdef DPLAY_VOICE_SUPPORT
#include "nmvoice.h"
#endif // DPLAY_VOICE_SUPPORT

#include "dpf.h"
#include "dputils.h"
#include "memalloc.h"
#include "resource.h"
#include <winsock2.h>
#include <ws2tcpip.h>
#include <ntddip6.h>

// to turn off SendEx support, comment this flag out.
#define SENDEX 1

// use ddraw's assert code (see orion\misc\dpf.h)
#define ASSERT DDASSERT

typedef WORD PORT;
typedef UINT SOCKERR;

// server ports
// Oops! We forgot to convert these constants to net byte order in the code so we
// are really using port 47624 (0xBA08) instead of 2234 (0x08BA)
// We are living with the mistake.
#define SERVER_STREAM_PORT 2234
#define SERVER_DGRAM_PORT 2234

// range of ports used by sp (these are properly converted in the code)
#define DPSP_MIN_PORT   2300
#define DPSP_MAX_PORT   2400
#define DPSP_NUM_PORTS   ((DPSP_MAX_PORT - DPSP_MIN_PORT)+1)

#define SPMESSAGEHEADERLEN (sizeof(DWORD))
#define DEFAULT_RECEIVE_BUFFERSIZE      (4*1024)        // default receive buffer size per connection

// token means this message was received from a remote
// dplay.  
#define TOKEN 0xFAB00000

// helper_token means this message was forwarded by our server helper (host)
#define HELPER_TOKEN 0xCAB00000

// server_token means this message is exchanged with dplaysvr (needed to distinguish 
// messages from a remote dpwsockx)
#define SERVER_TOKEN 0xBAB00000

// tells receiver to reuse the connection for replies (needed to support fullduplex
// connections)
#define REUSE_TOKEN 0xAAB00000


// masks
#define TOKEN_MASK 0xFFF00000
#define SIZE_MASK (~TOKEN_MASK)

// maxmessagelen = 2^20 (need 12 bits for token)
#define SPMAXMESSAGELEN ( 1048576 - 1)
#define VALID_SP_MESSAGE(pMsg) ( (*((DWORD *)pMsg) & TOKEN_MASK) == TOKEN ? TRUE : FALSE)
#define VALID_HELPER_MESSAGE(pMsg) ( (*((DWORD *)pMsg) & TOKEN_MASK) == HELPER_TOKEN ? TRUE : FALSE)
#define VALID_REUSE_MESSAGE(pMsg) ( (*((DWORD *)pMsg) & TOKEN_MASK) == REUSE_TOKEN ? TRUE : FALSE)
#define VALID_SERVER_MESSAGE(pMsg) ( (*((DWORD *)pMsg) & TOKEN_MASK) == SERVER_TOKEN ? TRUE : FALSE)
#define SP_MESSAGE_SIZE(pMsg) ( (*((DWORD *)pMsg) & SIZE_MASK))
#define SP_MESSAGE_TOKEN(pMsg) ( (*((DWORD *)pMsg) & TOKEN_MASK))

#define VALID_DPWS_MESSAGE(pMsg) (  VALID_SP_MESSAGE(pMsg) || VALID_HELPER_MESSAGE(pMsg) || \
                                                                        VALID_SERVER_MESSAGE(pMsg) || VALID_REUSE_MESSAGE(pMsg) )
#define VALID_DPLAYSVR_MESSAGE(pMsg) (  VALID_SP_MESSAGE(pMsg) || VALID_SERVER_MESSAGE(pMsg) || \
                                                                                VALID_REUSE_MESSAGE(pMsg) )

// relation of timeout to latency
#define TIMEOUT_SCALE 10
#define SPTIMEOUT(latency) (TIMEOUT_SCALE * latency)

// the default size of the socket cache (gBagOSockets)
#define MAX_CONNECTED_SOCKETS 64

// the initial size of the receive list
#define INITIAL_RECEIVELIST_SIZE 16

// version number for service provider
#define SPMINORVERSION      0x0000                              // service provider-specific version number
#define VERSIONNUMBER           (DPSP_MAJORVERSION | SPMINORVERSION) // version number for service provider

// biggest user enterable addess
#define ADDR_BUFFER_SIZE 128
                                                                 
// macro picks the service socket depending on ipx vs. tcp
// ipx uses dgram, tcp uses stream
#define SERVICE_SOCKET(pgd) ( pgd->sSystemStreamSocket)

//
// In order to listen to any number of sockets we need our own version
// of fd_set and FD_SET().  We call them fd_big_set and FD_BIG_SET().
//
typedef struct fd_big_set {
    u_int   fd_count;           // how many are SET?   
    SOCKET  fd_array[0];        // an array of SOCKETs 
} fd_big_set;

// stolen from winsock2.h

#ifndef _WINSOCK2API_

typedef HANDLE WSAEVENT;

typedef struct _WSAOVERLAPPED {
    DWORD        Internal;
    DWORD        InternalHigh;
    DWORD        Offset;
    DWORD        OffsetHigh;
    WSAEVENT     hEvent;
} WSAOVERLAPPED, FAR * LPWSAOVERLAPPED;

typedef struct _WSABUF {
    u_long      len;     /* the length of the buffer */
    char FAR *  buf;     /* the pointer to the buffer */
} WSABUF, FAR * LPWSABUF;
 
#endif // _WINSOCK2API_

#define MAX_SG 9
typedef WSABUF SENDARRAY[MAX_SG];
typedef SENDARRAY *PSENDARRAY;

#define SI_RELIABLE 0x0000001
#define SI_DATAGRAM 0x0000000

typedef struct _SENDINFO {
        WSAOVERLAPPED wsao;
        SENDARRAY     SendArray;        // Array of buffers
        DWORD         dwFlags;
        DWORD         dwSendFlags;  // DPLAY Send Flags.
        UINT          iFirstBuf;        // First buffer in array to use
        UINT          cBuffers;         // number of buffers to send (starting at iFirstBuf)
        BILINK        PendingSendQ; // when we're pending
        BILINK        ReadyToSendQ; // still waiting to send on this queue.
        DPID          idTo;
        DPID          idFrom;
        SOCKET        sSocket;          // reliable sends
        SOCKADDR_IN6  sockaddr;         // datagram sends
        DWORD_PTR     dwUserContext;
        DWORD         dwMessageSize;
        DWORD         RefCount;
        LONG          Status;
        struct _GLOBALDATA *pgd;
        IDirectPlaySP * lpISP;                  //  indication interface
        #ifdef DEBUG
        DWORD         wserr;                    // winsock extended error on wsasend call
        #endif
} SENDINFO, FAR *LPSENDINFO;

//
// This code is stolen from winsock.h.  It does the same thing as FD_SET()
// except that it assumes the fd_array is large enough.  AddSocketToReceiveList()
// grows the buffer as needed, so this better always be true.
//

#define FD_BIG_SET(fd, address) do { \
    ASSERT((address)->dwArraySize > (address)->pfdbigset->fd_count); \
    (address)->pfdbigset->fd_array[(address)->pfdbigset->fd_count++]=(fd);\
} while(0)

typedef struct fds {
        DWORD           dwArraySize;    // # of sockets that can be stored in pfdbigset->fd_array buffer
        fd_big_set      *pfdbigset;             
} FDS;

typedef struct _CONNECTION
{
        SOCKET  socket;                         // socket we can receive off of
        DWORD   dwCurMessageSize;       // current message size
        DWORD   dwTotalMessageSize;     // total message size
        SOCKADDR_IN6 sockAddr;  // addresses connected to
        LPBYTE  pBuffer;                        // points to either default or temporary receive buffer
        LPBYTE  pDefaultBuffer;         // default receive buffer (pBuffer points to this by default)
        // added in DX6
        DWORD   dwFlags;                        // connection attributes e.g. SP_CONNECION_FULLDUPLEX
} CONNECTION, *LPCONNECTION;

typedef struct _RECEIVELIST
{
        UINT nConnections;                      // how many peers are we connected to
        LPCONNECTION pConnection;// list of connections
} RECEIVELIST;

typedef struct _REPLYLIST * LPREPLYLIST;
typedef struct _REPLYLIST
{
        LPREPLYLIST pNextReply; // next reply in list
        LPVOID  lpMessage; // bufffer to send
        SOCKADDR_IN6 sockaddr;  // addr to send to
        DWORD dwMessageSize;
        SOCKET sSocket; // socket to send on
        LPBYTE pbSend; // index into message pointing to next byte to send
        DWORD  dwBytesLeft; // how many bytes are left to send
        DWORD  dwPlayerTo; // dpid of to player, 0=>not in use.
} REPLYLIST;

// w store one of these w/ each sys player
typedef struct _SPPLAYERDATA 
{
        SOCKADDR_IN6 saddrStream,saddrDatagram;
}SPPLAYERDATA,*LPSPPLAYERDATA;

        
// the message header
typedef struct _MESSAGEHEADER
{
        DWORD dwMessageSize; // size of message
        SOCKADDR_IN6 sockaddr;
} MESSAGEHEADER,*LPMESSAGEHEADER;


// this is one element in our bagosockets
typedef struct _PLAYERSOCK
{
        SOCKET sSocket;
        DPID dwPlayerID;
        // added in DX6
        SOCKADDR_IN6 sockaddr;
        DWORD dwFlags;                  // SP_CONNECTION_FULLDUPLEX, etc.
} PLAYERSOCK,*LPPLAYERSOCK;

// flags that describe a socket
#define SP_CONNECTION_FULLDUPLEX        0x00000001
// stream accept socket in the socket list.
#define SP_STREAM_ACCEPT            0x00000002  

#ifdef SENDEX
typedef struct FPOOL *LPFPOOL;
#endif

typedef struct _GLOBALDATA
{
        SOCKET sSystemDGramSocket;
        SOCKET sSystemStreamSocket;
        HANDLE hStreamReceiveThread;    // does receive and accept.
        HANDLE hDGramReceiveThread;
        HANDLE hReplyThread;
        RECEIVELIST ReceiveList;  // the list of sockets that StreamReceiveThread is listening on
        SOCKET sUnreliableSocket; // cached for unreliable send
        // reply thread 
        LPREPLYLIST pReplyList; // list of replies for reply thread to send
        HANDLE hReplyEvent; // signal the replythread that something is up
        // bago sockets stuff
        LPPLAYERSOCK BagOSockets; // socket cache
        UINT nSocketsInBag; // how many sockets in our bag
        SOCKADDR_IN6 saddrEnumAddress; // address entered by user for game server
        ULONG AddressFamily;
        SOCKADDR_IN6 saddrNS; // address for name server
        DWORD dwLatency; // from dwreserved1 in registry
        BOOL bShutdown;
        SOCKADDR_IN6 saddrControlSocket;
        BOOL bHaveServerAddress;
    CHAR szServerAddress[ADDR_BUFFER_SIZE];
        UINT iMaxUdpDg;                 // maximum udp datagram size
        // added in DX6
        FDS     readfds;                        // dynamic read fdset
        DWORD dwFlags;                  // DPSP_OUTBOUNDONLY, etc.
        DWORD dwSessionFlags;   // session flags passed by app
        WORD wApplicationPort;  // port used for creating system player sockets
#ifdef BIGMESSAGEDEFENSE
        DWORD   dwMaxMessageSize;       // the max message size we should receive
#endif

        HANDLE  hTCPEnumAsyncThread; // fix async enum.
        LPVOID  lpEnumMessage;
        DWORD   dwEnumMessageSize;
        SOCKADDR_IN6 saEnum;
        DWORD    dwEnumAddrSize;
        SOCKET   sEnum;
        BOOL     bOutBoundOnly;

#ifdef SENDEX
        CRITICAL_SECTION csSendEx;  // locks sendex data.
        LPFPOOL pSendInfoPool;     // pool for allocating SENDINFO+SPHeaders for scatter gather sends
        DWORD   dwBytesPending;         // count of total bytes in pending messages.
        DWORD   dwMessagesPending;  // count of total bytes pending.
        BILINK  PendingSendQ;
        BILINK  ReadyToSendQ;
        HANDLE  hSendWait;         // alert thread wait here.
        HANDLE  BogusHandle;       // don't be fooled by waitfor multiple probs in Win9x, put -1 here.
        BOOL    bSendThreadRunning;
        BOOL    bStopSendThread;
#endif

} GLOBALDATA,*LPGLOBALDATA;

/*
 * SP Flags (from registry)
 */
#define DPSP_OUTBOUNDONLY       0x00000001

/*
 * DPLAYSVR - DPWSOCKX communication related information
 */

// MSG_HDR indicates a dpwsock system message
#define MSG_HDR 0x736F636B

#define SP_MSG_VERSION  1       // DX6

#define IS_VALID_DPWS_MESSAGE(pMsg) (MSG_HDR == (*((DWORD *)(pMsg))) )
#define COMMAND_MASK 0X0000FFFF

#define GET_MESSAGE_VERSION(pMsg) ( ((pMsg)->dwCmdToken & ~COMMAND_MASK) >> 16 )
#define GET_MESSAGE_COMMAND(pMsg) ( (pMsg)->dwCmdToken & COMMAND_MASK)

#define SET_MESSAGE_HDR(pMsg)  (*((DWORD *)(pMsg)) = MSG_HDR )
#define SET_MESSAGE_COMMAND(pMsg,dwCmd) ((pMsg)->dwCmdToken = ((dwCmd & COMMAND_MASK) \
        | (SP_MSG_VERSION<<16)) )

typedef struct {
        DWORD dwHeader;
    DWORD dwCmdToken;   
} MSG_GENERIC, *LPMSG_GENERIC;


// DPLAYSVR


// macros for manipulating the sockaddr in the player data
#ifdef DEBUG
extern int gCSCount;
#endif
extern CRITICAL_SECTION gcsDPSPCritSection;     // defined in dllmain.c
#define INIT_DPSP_CSECT() InitializeCriticalSection(&gcsDPSPCritSection);
#define FINI_DPSP_CSECT() DeleteCriticalSection(&gcsDPSPCritSection);
#ifdef DEBUG
#define ENTER_DPSP() EnterCriticalSection(&gcsDPSPCritSection),gCSCount++;
#define LEAVE_DPSP() gCSCount--,LeaveCriticalSection(&gcsDPSPCritSection);
#else
#define ENTER_DPSP() EnterCriticalSection(&gcsDPSPCritSection);
#define LEAVE_DPSP() LeaveCriticalSection(&gcsDPSPCritSection);
#endif // DEBUG

// get a pointer to the players socket address - used by macros below
#define DGRAM_PSOCKADDR(ppd) ((SOCKADDR_IN6 *)&(((LPSPPLAYERDATA)ppd)->saddrDatagram))
#define STREAM_PSOCKADDR(ppd) ((SOCKADDR_IN6 *)&(((LPSPPLAYERDATA)ppd)->saddrStream))

// get the udp ip addr from a player
#define IP_DGRAM_PORT(ppd)      (DGRAM_PSOCKADDR(ppd)->sin6_port)

// get the stream ip addr from a player
#define IP_STREAM_PORT(ppd) (STREAM_PSOCKADDR(ppd)->sin6_port)

// used to get the name of the computer we're running on in spinit
#define HOST_NAME_LENGTH 50

// 84a22c0b-45af-4ad9-a4f1-4bf547f7d0d2
DEFINE_GUID(GUID_IPV6,
0x84a22c0b, 0x45af, 0x4ad9, 0xa4, 0xf1, 0x4b, 0xf5, 0x47, 0xf7, 0xd0, 0xd2);

// 0855c42a-4193-4ed1-bbbc-39a9c597157e
DEFINE_GUID(GUID_LOCAL_IPV6, 
0x0855c42a, 0x4193, 0x4ed1, 0xbb, 0xbc, 0x39, 0xa9, 0xc5, 0x97, 0x15, 0x7e);


// globals
// ghinstance is used when putting up the dialog box to prompt for ip addr
extern HANDLE ghInstance; // set in dllmain. instance handle for dpwsock.dll

extern const IN6_ADDR in6addr_multicast;
extern const SOCKADDR_IN6 sockaddr_any;

#ifdef DEBUG

extern void DebugPrintAddr(UINT level,LPSTR pStr,SOCKADDR * psockaddr);
#define DEBUGPRINTADDR(n,pstr,psockaddr) DebugPrintAddr(n,pstr,(LPSOCKADDR)psockaddr);
extern void DebugPrintSocket(UINT level,LPSTR pStr,SOCKET * pSock);
#define DEBUGPRINTSOCK(n,pstr,psock) DebugPrintSocket(n,pstr,psock);

#else // debug

#define DEBUGPRINTADDR(n,pstr,psockaddr)
#define DEBUGPRINTSOCK(n,pstr,psock)

#endif // debug

// global vars
extern BOOL gbVoiceOpen; // set to TRUE if we have nm call open

// from dpsp.c
#define IN6ADDR_MULTICAST_INIT {0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0x01,0x30}
extern HRESULT WaitForThread(HANDLE hThread);
extern HRESULT SetupControlSocket();
extern HRESULT WINAPI SP_Close(LPDPSP_CLOSEDATA pcd);
extern HRESULT InternalReliableSend(LPGLOBALDATA pgd, DPID idPlayerTo, SOCKADDR_IN6 *
        lpSockAddr, LPBYTE lpMessage, DWORD dwMessageSize);
extern HRESULT DoTCPEnumSessions(LPGLOBALDATA pgd, SOCKADDR *lpSockAddr, DWORD dwAddrSize,
        LPDPSP_ENUMSESSIONSDATA ped, BOOL bHostWillReuseConnection);
extern HRESULT SendControlMessage(LPGLOBALDATA pgd);
extern HRESULT SendReuseConnectionMessage(SOCKET sSocket);
extern HRESULT AddSocketToBag(LPGLOBALDATA pgd, SOCKET socket, DPID dpid, SOCKADDR_IN6 *psockaddr, DWORD dwFlags);
extern BOOL FindSocketInReceiveList(LPGLOBALDATA pgd, SOCKADDR *pSockAddr, SOCKET * psSocket);
extern void RemoveSocketFromReceiveList(LPGLOBALDATA pgd, SOCKET socket);
extern void RemoveSocketFromBag(LPGLOBALDATA pgd, SOCKET socket);
extern BOOL FindSocketInBag(LPGLOBALDATA pgd, SOCKADDR *pSockAddr, SOCKET * psSocket, LPDPID lpdpidPlayer);
extern HRESULT GetSocketFromBag(LPGLOBALDATA pgd,SOCKET * psSocket, DWORD dwID, LPSOCKADDR_IN6 psockaddr);
extern HRESULT CreateAndConnectSocket(LPGLOBALDATA pgd,SOCKET * psSocket,DWORD dwType,LPSOCKADDR_IN6 psockaddr, BOOL bOutBoundOnly);
extern void RemovePlayerFromSocketBag(LPGLOBALDATA pgd,DWORD dwID);
extern void SetMessageHeader(LPDWORD pdwMsg,DWORD dwSize, DWORD dwToken);
extern void KillTCPEnumAsyncThread(LPGLOBALDATA pgd);
extern SOCKET_ADDRESS_LIST *GetHostAddr(void);
extern void FreeHostAddr(SOCKET_ADDRESS_LIST *pList);

// Support for SendEx in dpsp.c

extern HRESULT UnreliableSendEx(LPDPSP_SENDEXDATA psd, LPSENDINFO lpSendInfo);
extern HRESULT ReliableSendEx(LPDPSP_SENDEXDATA psd, LPSENDINFO pSendInfo);
extern VOID RemovePendingAsyncSends(LPGLOBALDATA pgd, DPID dwPlayerTo);
extern BOOL bAsyncSendsPending(LPGLOBALDATA pgd, DPID dwPlayerTo);

// from winsock.c
extern HRESULT FAR PASCAL CreateSocket(LPGLOBALDATA pgd,SOCKET * psock,INT type,
        WORD port,const SOCKADDR_IN6 * psockaddr,SOCKERR * perr, BOOL bInRange);
extern HRESULT SPConnect(SOCKET* psSocket, LPSOCKADDR psockaddr,UINT addrlen, BOOL bOutBoundOnly);
extern HRESULT CreateAndInitStreamSocket(LPGLOBALDATA pgd);
extern HRESULT SetPlayerAddress(LPGLOBALDATA pgd,LPSPPLAYERDATA ppd,SOCKET sSocket,BOOL fStream); 
extern HRESULT CreatePlayerDgramSocket(LPGLOBALDATA pgd,LPSPPLAYERDATA ppd,DWORD dwFlags); 
extern HRESULT CreatePlayerStreamSocket(LPGLOBALDATA pgd,LPSPPLAYERDATA ppd,DWORD dwFlags); 
extern HRESULT SetDescriptionAddress(LPSPPLAYERDATA ppd,LPDPSESSIONDESC2 lpsdDesc);
extern HRESULT SetReturnAddress(LPVOID pmsg,SOCKET sSocket);
extern HRESULT GetReturnAddress(LPVOID pmsg,LPSOCKADDR_IN6 psockaddr);
extern HRESULT GetServerAddress(LPGLOBALDATA pgd,LPSOCKADDR_IN6 psockaddr) ;
extern void IP6_GetAddr(SOCKADDR_IN6 * paddrDest,SOCKADDR_IN6 * paddrSrc) ;
extern void IP6_SetAddr(LPVOID pBuffer,SOCKADDR_IN6 * psockaddr);
extern HRESULT KillSocket(SOCKET sSocket,BOOL fStream,BOOL fHard);
extern HRESULT KillPlayerSockets();
extern HRESULT GetAddress(SOCKADDR_IN6 * puAddress,char *pBuffer,int cch);
extern HRESULT KillThread(HANDLE hThread);

// from wsock2.c
extern DWORD WINAPI AsyncSendThreadProc(LPVOID pvCast);
extern HRESULT InitWinsock2();
extern HRESULT GetMaxUdpBufferSize(SOCKET socket, unsigned int * lpiSize);

extern HRESULT InternalReliableSendEx(LPGLOBALDATA pgd, LPDPSP_SENDEXDATA psd, 
                                LPSENDINFO pSendInfo, SOCKADDR_IN6 *lpSockAddr);
extern DWORD WINAPI SPSendThread(LPVOID lpv);

extern int Dplay_GetAddrInfo(const char FAR *nodename, const char FAR *servname,
                LPADDRINFO hints, ADDRINFO FAR * FAR * res);
extern void Dplay_FreeAddrInfo(LPADDRINFO pai);


#ifdef DPLAY_VOICE_SUPPORT
// from spvoice.c
extern HRESULT WINAPI SP_OpenVoice(LPDPSP_OPENVOICEDATA pod) ;
extern HRESULT WINAPI SP_CloseVoice(LPDPSP_CLOSEVOICEDATA pod) ;
#endif // DPLAY_VOICE_SUPPORT

// from handler.c
HRESULT HandleServerMessage(LPGLOBALDATA pgd, SOCKET sSocket, LPBYTE pBuffer, DWORD dwSize);

// from ipv6.c
extern DWORD ForEachInterface(void (*func)(IPV6_INFO_INTERFACE *, void *,void *,
                void *), void *Context1, void *Context2, void *Context3);
extern void ForEachAddress(IPV6_INFO_INTERFACE *IF, void 
                (*func)(IPV6_INFO_INTERFACE *IF, IPV6_INFO_ADDRESS *, void *), 
                void *);
extern UINT JoinEnumGroup(SOCKET sSocket, UINT ifindex);

#ifdef FULLDUPLEX_SUPPORT
// from registry.c
HRESULT GetFlagsFromRegistry(LPGUID lpguidSP, LPDWORD lpdwFlags);
#endif // FULLDUPLEX_SUPPORT

// MACROS based on fixed pool manager.

#endif