diff --git a/dlls/dpnet/Makefile.in b/dlls/dpnet/Makefile.in index 17929ea..e561796 100644 --- a/dlls/dpnet/Makefile.in +++ b/dlls/dpnet/Makefile.in @@ -4,18 +4,26 @@ SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = dpnet.dll IMPORTLIB = libdpnet.$(IMPLIBEXT) -IMPORTS = ole32 user32 advapi32 kernel32 +IMPORTS = ole32 user32 advapi32 kernel32 ws2_32 shlwapi EXTRALIBS = -ldxguid -luuid -C_SRCS = \ - address.c \ +C_SRCS = dpnet_main.c \ + dpnet_classfactory.c \ client.c \ - dpnet_main.c \ peer.c \ - regsvr.c \ - server.c + server.c \ + lobbiedapp.c \ + lobbyclient.c \ + address.c \ + general.c \ + threadpool.c \ + sp_tcpip.c \ + session.c \ + dialog.c \ + debug.c \ + parse.c -RC_SRCS = version.rc +RC_SRCS = hostname_En.rc version.rc @MAKE_DLL_RULES@ diff --git a/dlls/dpnet/address.c b/dlls/dpnet/address.c index 0e45b80..a689b53 100644 --- a/dlls/dpnet/address.c +++ b/dlls/dpnet/address.c @@ -1,7 +1,7 @@ -/* - * DirectPlay8 Address - * - * Copyright 2004 Raphael Junqueira +/* dpnet.dll + * + * Copyright (C) 2002-2007 TransGaming Inc. + * Written by: David Hammerton, Ove Kåven * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -16,260 +16,899 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - * */ -#include "config.h" - #include - -#define COBJMACROS +#include +#include #include "windef.h" #include "winbase.h" -#include "wingdi.h" #include "winuser.h" +#include "winreg.h" #include "objbase.h" #include "wine/debug.h" +#include "winerror.h" +#include "winnt.h" +#include "wine/unicode.h" + +#define NO_SHLWAPI_STREAM +#include "shlwapi.h" #include "dplay8.h" -#include "dpnet_private.h" +#include "dpaddr.h" +#include "dplay8_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dplay); + +static ICOM_VTABLE(IDirectPlay8Address) directPlay8AddressVT; +static ICOM_VTABLE(IDirectPlay8AddressIP) directPlay8AddressIPVT; +static DWORD GetDataType(const WCHAR * name); + +typedef struct dpna_types_t { + int index; + const WCHAR * name; + DWORD type; +} dpna_types_t; + +static dpna_types_t dpna_types[] = { + { 0, DPNA_KEY_PROVIDER, DPNA_DATATYPE_GUID }, + { 1, DPNA_KEY_APPLICATION_INSTANCE, DPNA_DATATYPE_GUID }, + { 2, DPNA_KEY_HOSTNAME, DPNA_DATATYPE_STRING }, + { 3, DPNA_KEY_BAUD, DPNA_DATATYPE_DWORD }, + { 4, DPNA_KEY_DEVICE, DPNA_DATATYPE_GUID }, + { 5, DPNA_KEY_FLOWCONTROL, DPNA_DATATYPE_STRING }, + { 6, DPNA_KEY_NAMEINFO, DPNA_DATATYPE_STRING }, + { 7, DPNA_KEY_NAT_RESOLVER, DPNA_DATATYPE_STRING }, + { 8, DPNA_KEY_NAT_RESOLVER_USER_STRING, DPNA_DATATYPE_STRING }, + { 9, DPNA_KEY_PARITY, DPNA_DATATYPE_STRING }, + { 10, DPNA_KEY_PHONENUMBER, DPNA_DATATYPE_STRING }, + { 11, DPNA_KEY_PORT, DPNA_DATATYPE_DWORD }, + { 12, DPNA_KEY_PROGRAM, DPNA_DATATYPE_GUID }, + { 13, DPNA_KEY_SCOPE, DPNA_DATATYPE_DWORD }, + { 14, DPNA_KEY_STOPBITS, DPNA_DATATYPE_DWORD }, + { 15, DPNA_KEY_TRAVERSALMODE, DPNA_DATATYPE_DWORD } +}; -WINE_DEFAULT_DEBUG_CHANNEL(dpnet); +#define MAX_DPNA_TYPES 16 -/* IDirectPlay8Address IUnknown parts follow: */ -static HRESULT WINAPI IDirectPlay8AddressImpl_QueryInterface(PDIRECTPLAY8ADDRESS iface, REFIID riid, LPVOID *ppobj) +/* convert a guid to a wstr */ +static void guid2wstr(const GUID *guid, LPWSTR wstr) { - IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface; + char str[40]; - if (IsEqualGUID(riid, &IID_IUnknown) - || IsEqualGUID(riid, &IID_IDirectPlay8Address)) { - IUnknown_AddRef(iface); - *ppobj = This; - return DPN_OK; + sprintf(str, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", + guid->Data1, guid->Data2, guid->Data3, + guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], + guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); + + MultiByteToWideChar(CP_ACP, 0, str, -1, wstr, 40); +} + +HRESULT WINAPI DirectPlay8Address_QueryInterface(PDIRECTPLAY8ADDRESS iface, + REFIID riid, LPVOID *obj) +{ + ICOM_THIS(IDirectPlay8AddressImpl, iface); + TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj); + if (IsEqualGUID(&IID_IUnknown, riid) || + IsEqualGUID(&IID_IDirectPlay8Address, riid)) + { + This->ref++; + *obj = This; + return S_OK; + } + else if (IsEqualGUID(&IID_IDirectPlay8AddressIP, riid)) + { + This->ref++; + *obj = (LPVOID *)&This->lpVtbl2; + return S_OK; } + else + { + FIXME("(%p)->(%s, %p): no interface\n", iface, debugstr_guid(riid), obj); + return E_NOINTERFACE; + } +} + +ULONG WINAPI DirectPlay8Address_AddRef(PDIRECTPLAY8ADDRESS iface) +{ + ICOM_THIS(IDirectPlay8AddressImpl, iface); + TRACE("(%p)->()\n", iface); + return ++This->ref; +} + +ULONG WINAPI DirectPlay8Address_Release(PDIRECTPLAY8ADDRESS iface) +{ + ICOM_THIS(IDirectPlay8AddressImpl, iface); + TRACE("(%p)->()\n", iface); + if (--This->ref) return This->ref; + + if (This->spData && !This->spDataRelease) FIXME("no release for data @ %p\n", This->spData); + if (This->spData) This->spDataRelease(This->spData); + while (This->component != NULL) { + struct AddressComponent * component = This->component; + This->component = This->component->next; + HeapFree(GetProcessHeap(), 0, component->pwszName); + HeapFree(GetProcessHeap(), 0, component->lpvData); + HeapFree(GetProcessHeap(), 0, component); + } + if (This->dwDataSize > 0) { + HeapFree(GetProcessHeap(), 0, This->pvUserData); + } + HeapFree(GetProcessHeap(), 0, This); + return 0; +} - WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj); - return E_NOINTERFACE; +HRESULT WINAPI DirectPlay8Address_BuildFromURLA(PDIRECTPLAY8ADDRESS iface, CHAR *pszSourceURL) +{ + /* ICOM_THIS(IDirectPlay8AddressImpl, iface); */ + + WCHAR *pwszSourceURL; + INT iUrlStringLen; + HRESULT hr; + + TRACE("(%p)->(%s)\n", iface, debugstr_a(pszSourceURL)); + + iUrlStringLen = strlen(pszSourceURL); + pwszSourceURL = HeapAlloc(GetProcessHeap(), 0, (iUrlStringLen + 1) * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pszSourceURL, iUrlStringLen, pwszSourceURL, + (iUrlStringLen + 1) * sizeof(WCHAR) / sizeof(CHAR)); + + hr = IDirectPlay8Address_BuildFromURLW(iface, pwszSourceURL); + + HeapFree(GetProcessHeap(), 0, pwszSourceURL); + + return hr; } -static ULONG WINAPI IDirectPlay8AddressImpl_AddRef(PDIRECTPLAY8ADDRESS iface) { - IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface; - ULONG refCount = InterlockedIncrement(&This->ref); +HRESULT WINAPI DirectPlay8Address_BuildFromURLW(PDIRECTPLAY8ADDRESS iface, WCHAR *pwszSourceURL) +{ + /*ICOM_THIS(IDirectPlay8AddressImpl, iface);*/ + WCHAR *provider = NULL; + DWORD providerLen = 0; + GUID guidSP; + int i; + + TRACE("(%p)->(%s)\n", iface, debugstr_w(pwszSourceURL)); - TRACE("(%p)->(ref before=%u)\n", This, refCount - 1); + if (strncmpW(pwszSourceURL, DPNA_HEADER, strlenW(DPNA_HEADER)) != 0) + return DPNERR_INVALIDURL; - return refCount; + /* First, clear the old data out*/ + IDirectPlay8Address_Clear(iface); + + if (DPNET_GetKeyValueW(pwszSourceURL, DPNA_KEY_PROVIDER, provider, &providerLen) + != DPNERR_BUFFERTOOSMALL) + { + return DPNERR_INVALIDURL; + } + + provider = HeapAlloc(GetProcessHeap(), 0, providerLen * sizeof(WCHAR)); + DPNET_GetKeyValueW(pwszSourceURL, DPNA_KEY_PROVIDER, provider, &providerLen); + UrlUnescapeW(provider, NULL, NULL, URL_UNESCAPE_INPLACE); + CLSIDFromString(provider, &guidSP); + HeapFree(GetProcessHeap(), 0, provider); + IDirectPlay8Address_SetSP(iface, &guidSP); + + /* start at 1 so we skip the provider we just added */ + for (i = 1; i < MAX_DPNA_TYPES; i++) { + WCHAR attr[128]; + void * datum = NULL; + DWORD len = 0; + DWORD type; + + strcpyW(attr, dpna_types[i].name); + type = dpna_types[i].type; + if (DPNET_GetKeyValueW(pwszSourceURL, (const WCHAR *)attr, NULL, + &len) == DPNERR_BUFFERTOOSMALL) + { + datum = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + DPNET_GetKeyValueW(pwszSourceURL, attr, datum, &len); + IDirectPlay8Address_AddComponent(iface, attr, datum, len, type); + HeapFree(GetProcessHeap(), 0, datum); + } + } + + return S_OK; } -static ULONG WINAPI IDirectPlay8AddressImpl_Release(PDIRECTPLAY8ADDRESS iface) { - IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface; - ULONG refCount = InterlockedDecrement(&This->ref); +HRESULT WINAPI DirectPlay8Address_Duplicate(PDIRECTPLAY8ADDRESS iface, PDIRECTPLAY8ADDRESS *ppdpaNewAddress) +{ + /* ICOM_THIS(IDirectPlay8AddressImpl, iface); */ + HRESULT hr; + + TRACE("(%p)->(%p)\n", iface, ppdpaNewAddress); + hr = DPNET_CreateDirectPlay8Address(NULL, &IID_IDirectPlay8Address, (LPVOID *) ppdpaNewAddress); + if (!SUCCEEDED(hr)) + { + TRACE("duplication failed\n"); + return hr; + } - TRACE("(%p)->(ref before=%u)\n", This, refCount + 1); + hr = IDirectPlay8Address_SetEqual(*ppdpaNewAddress, iface); - if (!refCount) { - HeapFree(GetProcessHeap(), 0, This); + if (!SUCCEEDED(hr)) + { + IDirectPlay8Address_Release(*ppdpaNewAddress); + *ppdpaNewAddress = NULL; + TRACE("duplication failed\n"); + return hr; } - return refCount; + + TRACE("duplicated\n"); + + return hr; } -/* IDirectPlay8Address Interface follow: */ +HRESULT WINAPI DirectPlay8Address_SetEqual(PDIRECTPLAY8ADDRESS iface, PDIRECTPLAY8ADDRESS pdpaAddress) +{ + ICOM_THIS(IDirectPlay8AddressImpl, iface); + IDirectPlay8AddressImpl *otherThis = (IDirectPlay8AddressImpl *)pdpaAddress; + struct AddressComponent *comp; + struct AddressComponent *last; + + TRACE("(%p)->(%p)\n", iface, pdpaAddress); + + IDirectPlay8Address_Clear(iface); -static HRESULT WINAPI IDirectPlay8AddressImpl_BuildFromURLW(PDIRECTPLAY8ADDRESS iface, WCHAR* pwszSourceURL) { - IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface; - TRACE("(%p, %s): stub\n", This, debugstr_w(pwszSourceURL)); - return DPN_OK; + memcpy(&This->guidSP, &otherThis->guidSP, sizeof(GUID)); + memcpy(&This->guidDevice, &otherThis->guidDevice, sizeof(GUID)); + + comp = otherThis->component; + last = NULL; + while (comp) { + struct AddressComponent *component; + component = HeapAlloc(GetProcessHeap(), 0, sizeof(struct AddressComponent)); + component->pwszName = HeapAlloc(GetProcessHeap(), 0, (strlenW(comp->pwszName)+1) * sizeof(WCHAR)); + component->lpvData = HeapAlloc(GetProcessHeap(), 0, comp->dwDataSize); + component->dwDataSize = comp->dwDataSize; + component->dwDataType = comp->dwDataType; + strcpyW(component->pwszName, comp->pwszName); + memcpy(component->lpvData, comp->lpvData, component->dwDataSize); + + component->next = NULL; + + if (last) last->next = component; + else This->component = component; + last = component; + + comp = comp->next; + } + + if (otherThis->spData) otherThis->spDataDuplicate(iface, otherThis->spData); + + return S_OK; } -static HRESULT WINAPI IDirectPlay8AddressImpl_BuildFromURLA(PDIRECTPLAY8ADDRESS iface, CHAR* pszSourceURL) { - IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface; - TRACE("(%p, %s): stub\n", This, pszSourceURL); - return DPN_OK; +HRESULT WINAPI DirectPlay8Address_IsEqual(PDIRECTPLAY8ADDRESS iface, PDIRECTPLAY8ADDRESS pdpaAddress) +{ + /* ICOM_THIS(IDirectPlay8AddressImpl, iface); */ + /* IDirectPlay8AddressImpl *otherThis = (IDirectPlay8AddressImpl *)pdpaAddress; */ + + FIXME("(%p)->(%p): stub\n", iface, pdpaAddress); + + return DPNSUCCESS_NOTEQUAL; } -static HRESULT WINAPI IDirectPlay8AddressImpl_Duplicate(PDIRECTPLAY8ADDRESS iface, PDIRECTPLAY8ADDRESS* ppdpaNewAddress) { - IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface; - TRACE("(%p, %p): stub\n", This, ppdpaNewAddress); - return DPN_OK; +HRESULT WINAPI DirectPlay8Address_Clear(PDIRECTPLAY8ADDRESS iface) +{ + ICOM_THIS(IDirectPlay8AddressImpl, iface); + + TRACE("(%p)->()\n", iface); + + while (This->component != NULL) { + struct AddressComponent * component = This->component; + This->component = This->component->next; + HeapFree(GetProcessHeap(), 0, component->pwszName); + HeapFree(GetProcessHeap(), 0, component->lpvData); + HeapFree(GetProcessHeap(), 0, component); + } + if (This->dwDataSize > 0) { + HeapFree(GetProcessHeap(), 0, This->pvUserData); + This->dwDataSize = 0; + } + + if (This->spData) This->spDataRelease(This->spData); + This->spData = NULL; + + return S_OK; } -static HRESULT WINAPI IDirectPlay8AddressImpl_SetEqual(PDIRECTPLAY8ADDRESS iface, PDIRECTPLAY8ADDRESS pdpaAddress) { - IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface; - TRACE("(%p, %p): stub\n", This, pdpaAddress); - return DPN_OK; +HRESULT WINAPI DirectPlay8Address_GetURLW(PDIRECTPLAY8ADDRESS iface, WCHAR *pwszURL, PDWORD pdwNumChars) +{ + ICOM_THIS(IDirectPlay8AddressImpl, iface); + DWORD numCharsRequired = 0; + WCHAR * url = NULL; + DWORD i = 1; + DWORD urlsize = 0; + struct AddressComponent *component; + WCHAR wide[1024]; + WCHAR equals[] = {'=', 0}; + WCHAR pound[] = {'#', 0}; + WCHAR semicolon[] = {';', 0}; + + TRACE("(%p)->(%p, %p (%i))\n", iface, pwszURL, pdwNumChars, *pdwNumChars); + + /* If no GUID is set or no components have been added, we're done */ + if (IsEqualGUID(&This->guidSP, &GUID_NULL) || This->component == NULL) { + return DPNERR_INVALIDURL; + } + + /* First compute the size of the URL. This is a pretty rough "guess" and + * will likely be a tad too big but we'll get the "right" number later. */ + component = This->component; + while (component != NULL) { + if (component->dwDataType == GetDataType(component->pwszName)) { + urlsize += component->dwDataSize; + urlsize += strlenW(component->pwszName) + 2; /* include = and ; */ + if (component->dwDataType == DPNA_DATATYPE_GUID) { + urlsize += 6; /* handle escaping */ + } + } + component = component->next; + } + + urlsize += 46; /* for the escaped provider GUID */ + urlsize += strlenW(DPNA_HEADER) + 2; /* include /: */ + urlsize += strlenW(DPNA_KEY_PROVIDER) + 2; /* include = and ; */ + urlsize += This->dwDataSize; /* user data */ + + /* This should always be true, but should still check it */ + if (urlsize > 0) { + DWORD needed = 46; + url = HeapAlloc(GetProcessHeap(), 0, urlsize * sizeof(WCHAR)); + + strcpyW(url, DPNA_HEADER); /* x-directplay:/ */ + strcatW(url, DPNA_KEY_PROVIDER); /* provider */ + strcatW(url, equals); + + StringFromGUID2(&This->guidSP, wide, sizeof(wide)); + UrlEscapeW(wide, url + strlenW(url), &needed, 0); + + strcatW(url, semicolon); + component = This->component; + + while (component != NULL) { + strcatW(url, component->pwszName); + strcatW(url, equals); + switch (component->dwDataType) { + case DPNA_DATATYPE_STRING: + strcatW(url, component->lpvData); + break; + case DPNA_DATATYPE_DWORD: + { + const WCHAR fmt[] = {'%', 'l', 'd', 0}; + wsprintfW(wide, fmt, *((const DWORD *)component->lpvData)); + strcatW(url, wide); + break; + } + case DPNA_DATATYPE_GUID: + { + guid2wstr((GUID*)component->lpvData, wide); + strcatW(url, wide); + } + default: + WARN("Unhandled data type %d\n", component->dwDataType); + break; + } + strcatW(url, semicolon); + i++; + component = component->next; + } /* while */ + } + + /* remove the trailing semi-colon */ + url[strlenW(url)-1] = '\0'; + + if (This->dwDataSize > 0) { + strcatW(url, pound); + strcatW(url, This->pvUserData); + } + + numCharsRequired = strlenW(url) + 1; /* null term */ + if (*pdwNumChars < numCharsRequired) + { + *pdwNumChars = numCharsRequired; + HeapFree(GetProcessHeap(), 0, url); + return DPNERR_BUFFERTOOSMALL; + } + if (pwszURL != NULL) + { + strcpyW(pwszURL, url); + *pdwNumChars = numCharsRequired; + } + HeapFree(GetProcessHeap(), 0, url); + return S_OK; } -static HRESULT WINAPI IDirectPlay8AddressImpl_IsEqual(PDIRECTPLAY8ADDRESS iface, PDIRECTPLAY8ADDRESS pdpaAddress) { - IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface; - TRACE("(%p, %p): stub\n", This, pdpaAddress); - return DPN_OK; +HRESULT WINAPI DirectPlay8Address_GetURLA(PDIRECTPLAY8ADDRESS iface, CHAR *pszURL, PDWORD pdwNumChars) +{ + /* ICOM_THIS(IDirectPlay8AddressImpl, iface); */ + DWORD numCharsRequired = 0; + WCHAR * url = NULL; + HRESULT hr; + + TRACE("(%p)->(%p, %p (%i))\n", iface, pszURL, pdwNumChars, *pdwNumChars); + + hr = IDirectPlay8Address_GetURLW(iface, NULL, &numCharsRequired); + if (hr != S_OK && hr != DPNERR_BUFFERTOOSMALL) return hr; + + url = HeapAlloc(GetProcessHeap(), 0, numCharsRequired * sizeof(WCHAR)); + hr = IDirectPlay8Address_GetURLW(iface, url, &numCharsRequired); + if (hr == S_OK) { + INT len = WideCharToMultiByte(CP_ACP, 0, url, numCharsRequired, NULL, 0, NULL, NULL); + if (*pdwNumChars < len) { + *pdwNumChars = len; + hr = DPNERR_BUFFERTOOSMALL; + } else + if (pszURL) { + WideCharToMultiByte(CP_ACP, 0, url, numCharsRequired, pszURL, *pdwNumChars, NULL, NULL); + *pdwNumChars = len; + } + } + HeapFree(GetProcessHeap(), 0, url); + return hr; } -static HRESULT WINAPI IDirectPlay8AddressImpl_Clear(PDIRECTPLAY8ADDRESS iface) { - IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface; - TRACE("(%p): stub\n", This); - return DPN_OK; +HRESULT WINAPI DirectPlay8Address_GetSP(PDIRECTPLAY8ADDRESS iface, GUID *pguidSP) +{ + ICOM_THIS(IDirectPlay8AddressImpl, iface); + + TRACE("(%p)->(%s)\n", iface, debugstr_guid(pguidSP)); + + if (IsEqualGUID(&This->guidSP, &GUID_NULL)) { + return DPNERR_DOESNOTEXIST; + } + memcpy(pguidSP, &This->guidSP, sizeof(GUID)); + return S_OK; } -static HRESULT WINAPI IDirectPlay8AddressImpl_GetURLW(PDIRECTPLAY8ADDRESS iface, WCHAR* pwszURL, PDWORD pdwNumChars) { - IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface; - TRACE("(%p): stub\n", This); - return DPN_OK; +HRESULT WINAPI DirectPlay8Address_GetUserData(PDIRECTPLAY8ADDRESS iface, + void *pvUserData, + PDWORD pdwBufferSize +) +{ + ICOM_THIS(IDirectPlay8AddressImpl, iface); + + TRACE("(%p)->(%p, %p)\n", iface, pvUserData, pdwBufferSize); + + if (pvUserData == NULL && pdwBufferSize == 0) { + *pdwBufferSize = This->dwDataSize; + return DPNERR_BUFFERTOOSMALL; + } else { + if (*pdwBufferSize < This->dwDataSize) { + *pdwBufferSize = This->dwDataSize; + return DPNERR_BUFFERTOOSMALL; + } + memcpy(pvUserData, This->pvUserData, This->dwDataSize); + /* Size only gets set when in "query" mode */ + if (*pdwBufferSize == 0) + *pdwBufferSize = This->dwDataSize; + } + + return S_OK; } -static HRESULT WINAPI IDirectPlay8AddressImpl_GetURLA(PDIRECTPLAY8ADDRESS iface, CHAR* pszURL, PDWORD pdwNumChars) { - IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface; - TRACE("(%p): stub\n", This); - return DPN_OK; +HRESULT WINAPI DirectPlay8Address_SetSP(PDIRECTPLAY8ADDRESS iface, const GUID *const pguidSP) +{ + ICOM_THIS(IDirectPlay8AddressImpl, iface); + + TRACE("(%p)->(%s)\n", iface, debugstr_guid(pguidSP)); + memcpy(&This->guidSP, pguidSP, sizeof(GUID)); + return S_OK; } -static HRESULT WINAPI IDirectPlay8AddressImpl_GetSP(PDIRECTPLAY8ADDRESS iface, GUID* pguidSP) { - IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface; - TRACE("(%p, %p)\n", iface, pguidSP); - memcpy(pguidSP, &This->SP_guid, sizeof(GUID)); - return DPN_OK; +HRESULT WINAPI DirectPlay8Address_SetUserData(PDIRECTPLAY8ADDRESS iface, + const void *const pvUserData, + const DWORD dwDataSize) +{ + ICOM_THIS(IDirectPlay8AddressImpl, iface); + + TRACE("(%p)->(%s, %d)\n", iface, debugstr_w(pvUserData), dwDataSize); + + if (pvUserData == NULL && dwDataSize != 0) + return DPNERR_NOTALLOWED; + + if (This->dwDataSize > 0) { + HeapFree(GetProcessHeap(), 0, This->pvUserData); + This->dwDataSize = 0; + } + if (pvUserData != NULL) { + This->pvUserData = HeapAlloc(GetProcessHeap(), 0, dwDataSize); + memcpy(This->pvUserData, (void *)pvUserData, dwDataSize); + } else { + This->pvUserData = NULL; + } + This->dwDataSize = dwDataSize; + + return S_OK; } -static HRESULT WINAPI IDirectPlay8AddressImpl_GetUserData(PDIRECTPLAY8ADDRESS iface, LPVOID pvUserData, PDWORD pdwBufferSize) { - IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface; - TRACE("(%p): stub\n", This); - return DPN_OK; +HRESULT WINAPI DirectPlay8Address_GetNumComponents(PDIRECTPLAY8ADDRESS iface, PDWORD pdwNumComponents) +{ + DWORD count = 1; /* DX9 returns the # of components +1 for some reason */ + struct AddressComponent *c; + + ICOM_THIS(IDirectPlay8AddressImpl, iface); + + TRACE("(%p)->(%p)\n", iface, pdwNumComponents); + + c = This->component; + + while (c != NULL) { + count++; + c = c->next; + } + + TRACE("count: %d\n", count); + + *pdwNumComponents = count; + + return S_OK; } -static HRESULT WINAPI IDirectPlay8AddressImpl_SetSP(PDIRECTPLAY8ADDRESS iface, CONST GUID* CONST pguidSP) { - IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface; - TRACE("(%p, %s)\n", iface, debugstr_SP(pguidSP)); - memcpy(&This->SP_guid, pguidSP, sizeof(GUID)); - return DPN_OK; +HRESULT WINAPI DirectPlay8Address_GetComponentByName(PDIRECTPLAY8ADDRESS iface, + const WCHAR *const pwszName, + void *pvBuffer, + PDWORD pdwBufferSize, + PDWORD pdwDataType) +{ + struct AddressComponent *component; + HRESULT ret = DPNERR_DOESNOTEXIST; + + ICOM_THIS(IDirectPlay8AddressImpl, iface); + + TRACE("(%p)->(%s, %p, %p (%d), %p)\n", iface, + debugstr_w(pwszName), pvBuffer, pdwBufferSize, + *pdwBufferSize, pdwDataType); + + if (pdwBufferSize == NULL) + return DPNERR_INVALIDPARAM; + + component = This->component; + + while (component != NULL) { + if (!strcmpW(component->pwszName, pwszName)) { + if (*pdwBufferSize >= component->dwDataSize) { + *pdwDataType = component->dwDataType; + if (component->dwDataType == DPNA_DATATYPE_STRING) { + strcpyW(pvBuffer, component->lpvData); + } else + memcpy(pvBuffer, component->lpvData, component->dwDataSize); + ret = S_OK; + } else { + ret = DPNERR_BUFFERTOOSMALL; + } + *pdwBufferSize = component->dwDataSize; + break; + } + component = component->next; + } + + TRACE("returning %x\n", ret); + return ret; } -static HRESULT WINAPI IDirectPlay8AddressImpl_SetUserData(PDIRECTPLAY8ADDRESS iface, CONST void* CONST pvUserData, CONST DWORD dwDataSize) { - IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface; - TRACE("(%p): stub\n", This); - return DPN_OK; +HRESULT WINAPI DirectPlay8Address_GetComponentByIndex(PDIRECTPLAY8ADDRESS iface, + const DWORD dwComponentID, + WCHAR *pwszName, + PDWORD pdwNameLen, + void *pvBuffer, + PDWORD pdwBufferSize, + PDWORD pdwDataType +) +{ + struct AddressComponent *component; + HRESULT ret = DPNERR_DOESNOTEXIST; + int i = 0; + + ICOM_THIS(IDirectPlay8AddressImpl, iface); + + TRACE("(%p)->(%d, %p, %p, %p, %p, %p)\n", iface, dwComponentID, + pwszName, pdwNameLen, pvBuffer, pdwBufferSize, + pdwDataType); + + if (pdwBufferSize == NULL || pdwNameLen == NULL) + return DPNERR_INVALIDPARAM; + + component = This->component; + + while (component != NULL && i < dwComponentID - 1) { + i++; + component = component->next; + } + if (component) { + if (*pdwBufferSize >= component->dwDataSize && *pdwNameLen >= strlenW(component->pwszName)) { + *pdwDataType = component->dwDataType; + memcpy(pvBuffer, component->lpvData, component->dwDataSize); + strcpyW(pwszName, component->pwszName); + ret = S_OK; + } else { + ret = DPNERR_BUFFERTOOSMALL; + } + *pdwBufferSize = component->dwDataSize; + *pdwNameLen = strlenW(component->pwszName); + } + + TRACE("returning %x len=%d\n", ret, *pdwBufferSize); + + return ret; } -static HRESULT WINAPI IDirectPlay8AddressImpl_GetNumComponents(PDIRECTPLAY8ADDRESS iface, PDWORD pdwNumComponents) { - IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface; - TRACE("(%p): stub\n", This); - return DPN_OK; +HRESULT WINAPI DirectPlay8Address_AddComponent(PDIRECTPLAY8ADDRESS iface, + const WCHAR *const pwszName, + const void *const lpvData, + const DWORD dwDataSize, + const DWORD dwDataType) +{ + struct AddressComponent *component; + int found = 0; + + ICOM_THIS(IDirectPlay8AddressImpl, iface); + + TRACE("(%p)->(%s, %p, %d, %d)\n", iface, + debugstr_w(pwszName), lpvData, + dwDataSize, dwDataType); + + if (dwDataType != GetDataType(pwszName)) { + TRACE("=> invalidparam\n"); + return DPNERR_INVALIDPARAM; + } + + component = This->component; + while (component) { + if (!strcmpW(component->pwszName, pwszName)) { + HeapFree(GetProcessHeap(), 0, component->pwszName); + HeapFree(GetProcessHeap(), 0, component->lpvData); + found = 1; + break; + } + component = component->next; + } + if (!found) + component = HeapAlloc(GetProcessHeap(), 0, sizeof(struct AddressComponent)); + component->pwszName = HeapAlloc(GetProcessHeap(), 0, (strlenW(pwszName)+1) * sizeof(WCHAR)); + component->lpvData = HeapAlloc(GetProcessHeap(), 0, dwDataSize); + component->dwDataSize = dwDataSize; + component->dwDataType = dwDataType; + strcpyW(component->pwszName, pwszName); + + switch(dwDataType) { + case DPNA_DATATYPE_STRING: + strcpyW(component->lpvData, lpvData); + TRACE("string is %s\n", debugstr_w(lpvData)); + break; + case DPNA_DATATYPE_DWORD: + TRACE("%d (%d)\n", *((const DWORD *)lpvData), dwDataSize); + default: + memcpy(component->lpvData, lpvData, dwDataSize); + break; + } + + if (found) { /* we are updating an existing entry */ + return S_OK; + } + + component->next = NULL; + + /* Put new element onto the end of the list. This is necessary so the user + * can call GetComponentByIndex and expect the component to be stored in + * the order it was added. */ + if (This->component == NULL) { + This->component = component; + } else { + struct AddressComponent *temp; + temp = This->component; + while (temp->next != NULL) { + temp = temp->next; + } + temp->next = component; + } + + return S_OK; } -static HRESULT WINAPI IDirectPlay8AddressImpl_GetComponentByName(PDIRECTPLAY8ADDRESS iface, CONST WCHAR* CONST pwszName, LPVOID pvBuffer, PDWORD pdwBufferSize, PDWORD pdwDataType) { - IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface; - TRACE("(%p): stub\n", This); - return DPN_OK; +HRESULT WINAPI DirectPlay8Address_SetDevice(PDIRECTPLAY8ADDRESS iface, const GUID *const pguidDevice) +{ + ICOM_THIS(IDirectPlay8AddressImpl, iface); + + TRACE("(%p)->(%s)\n", iface, debugstr_guid(pguidDevice)); + memcpy(&This->guidDevice, pguidDevice, sizeof(GUID)); + return S_OK; } -static HRESULT WINAPI IDirectPlay8AddressImpl_GetComponentByIndex(PDIRECTPLAY8ADDRESS iface, CONST DWORD dwComponentID, WCHAR* pwszName, - PDWORD pdwNameLen, void* pvBuffer, PDWORD pdwBufferSize, PDWORD pdwDataType) { - IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface; - TRACE("(%p): stub\n", This); - return DPN_OK; +HRESULT WINAPI DirectPlay8Address_GetDevice(PDIRECTPLAY8ADDRESS iface, GUID *pguidDevice) +{ + ICOM_THIS(IDirectPlay8AddressImpl, iface); + + TRACE("(%p)->(%p)\n", iface, pguidDevice); + if (IsEqualGUID(&This->guidDevice, &GUID_NULL)) { + return DPNERR_DOESNOTEXIST; + } + memcpy(pguidDevice, &This->guidDevice, sizeof(GUID)); + return S_OK; } -static HRESULT WINAPI IDirectPlay8AddressImpl_AddComponent(PDIRECTPLAY8ADDRESS iface, CONST WCHAR* CONST pwszName, - CONST void* CONST lpvData, CONST DWORD dwDataSize, CONST DWORD dwDataType) { - IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface; - TRACE("(%p, %s, %p, %u, %x): stub\n", This, debugstr_w(pwszName), lpvData, dwDataSize, dwDataType); - - if (NULL == lpvData) return DPNERR_INVALIDPOINTER; - switch (dwDataType) { - case DPNA_DATATYPE_DWORD: - if (sizeof(DWORD) != dwDataSize) return DPNERR_INVALIDPARAM; - TRACE("(%p, %u): DWORD Type -> %u\n", lpvData, dwDataSize, *(const DWORD*) lpvData); - break; - case DPNA_DATATYPE_GUID: - if (sizeof(GUID) != dwDataSize) return DPNERR_INVALIDPARAM; - TRACE("(%p, %u): GUID Type -> %s\n", lpvData, dwDataSize, debugstr_guid((const GUID*) lpvData)); - break; - case DPNA_DATATYPE_STRING: - TRACE("(%p, %u): STRING Type -> %s\n", lpvData, dwDataSize, (const CHAR*) lpvData); - break; - case DPNA_DATATYPE_BINARY: - TRACE("(%p, %u): BINARY Type\n", lpvData, dwDataSize); - break; - } - - return DPN_OK; +HRESULT DPNET_CreateDirectPlay8Address(IUnknown *pOuter, REFIID riid, LPVOID *ppobj) +{ + IDirectPlay8AddressImpl *ipDP8A; + HRESULT hr; + TRACE("()\n"); + ipDP8A = (IDirectPlay8AddressImpl *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(IDirectPlay8AddressImpl)); + if (ipDP8A == NULL) return E_OUTOFMEMORY; + ICOM_VTBL(ipDP8A) = &directPlay8AddressVT; + ipDP8A->lpVtbl2 = &directPlay8AddressIPVT; + IDirectPlay8Address_AddRef((IDirectPlay8Address *)ipDP8A); + ipDP8A->component = NULL; + ipDP8A->pvUserData = NULL; + ipDP8A->dwDataSize = 0; + ipDP8A->guidDevice = GUID_NULL; + ipDP8A->guidSP = GUID_NULL; + TRACE("Created new object: %p\n", ipDP8A); + hr = IDirectPlay8Address_QueryInterface((IDirectPlay8Address *)ipDP8A, riid, ppobj); + IDirectPlay8Address_Release((IDirectPlay8Address *)ipDP8A); + + ipDP8A->hDialogMutex = CreateMutexA(NULL, FALSE, "DPNET Address DialogMutex"); + if (SUCCEEDED(hr)) + return S_OK; + else + return E_NOINTERFACE; } -static HRESULT WINAPI IDirectPlay8AddressImpl_GetDevice(PDIRECTPLAY8ADDRESS iface, GUID* pDevGuid) { - IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface; - TRACE("(%p): stub\n", This); - return DPN_OK; +/* DirectPlayAddressIP wrappers */ +HRESULT WINAPI DirectPlay8AddressIP_QueryInterface(PDIRECTPLAY8ADDRESSIP iface, + REFIID riid, LPVOID *obj) +{ + ICOM_THIS_MULTI(IDirectPlay8AddressImpl, lpVtbl2, iface); + TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj); + return IDirectPlay8Address_QueryInterface((PDIRECTPLAY8ADDRESS) This, riid, obj); } -static HRESULT WINAPI IDirectPlay8AddressImpl_SetDevice(PDIRECTPLAY8ADDRESS iface, CONST GUID* CONST devGuid) { - IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface; - TRACE("(%p, %s): stub\n", This, debugstr_guid(devGuid)); - return DPN_OK; +ULONG WINAPI DirectPlay8AddressIP_AddRef(PDIRECTPLAY8ADDRESSIP iface) +{ + ICOM_THIS_MULTI(IDirectPlay8AddressImpl, lpVtbl2, iface); + TRACE("(%p)->()\n", iface); + return IDirectPlay8Address_AddRef((PDIRECTPLAY8ADDRESS) This); } -static HRESULT WINAPI IDirectPlay8AddressImpl_BuildFromDirectPlay4Address(PDIRECTPLAY8ADDRESS iface, LPVOID pvAddress, DWORD dwDataSize) { - IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface; - TRACE("(%p): stub\n", This); - return DPN_OK; +ULONG WINAPI DirectPlay8AddressIP_Release(PDIRECTPLAY8ADDRESSIP iface) +{ + ICOM_THIS_MULTI(IDirectPlay8AddressImpl, lpVtbl2, iface); + TRACE("(%p)->()\n", iface); + return IDirectPlay8Address_Release((PDIRECTPLAY8ADDRESS) This); } -static const IDirectPlay8AddressVtbl DirectPlay8Address_Vtbl = +static ICOM_VTABLE(IDirectPlay8Address) directPlay8AddressVT = { - IDirectPlay8AddressImpl_QueryInterface, - IDirectPlay8AddressImpl_AddRef, - IDirectPlay8AddressImpl_Release, - IDirectPlay8AddressImpl_BuildFromURLW, - IDirectPlay8AddressImpl_BuildFromURLA, - IDirectPlay8AddressImpl_Duplicate, - IDirectPlay8AddressImpl_SetEqual, - IDirectPlay8AddressImpl_IsEqual, - IDirectPlay8AddressImpl_Clear, - IDirectPlay8AddressImpl_GetURLW, - IDirectPlay8AddressImpl_GetURLA, - IDirectPlay8AddressImpl_GetSP, - IDirectPlay8AddressImpl_GetUserData, - IDirectPlay8AddressImpl_SetSP, - IDirectPlay8AddressImpl_SetUserData, - IDirectPlay8AddressImpl_GetNumComponents, - IDirectPlay8AddressImpl_GetComponentByName, - IDirectPlay8AddressImpl_GetComponentByIndex, - IDirectPlay8AddressImpl_AddComponent, - IDirectPlay8AddressImpl_GetDevice, - IDirectPlay8AddressImpl_SetDevice, - IDirectPlay8AddressImpl_BuildFromDirectPlay4Address + DirectPlay8Address_QueryInterface, + DirectPlay8Address_AddRef, + DirectPlay8Address_Release, + DirectPlay8Address_BuildFromURLW, + DirectPlay8Address_BuildFromURLA, + DirectPlay8Address_Duplicate, + DirectPlay8Address_SetEqual, + DirectPlay8Address_IsEqual, + DirectPlay8Address_Clear, + DirectPlay8Address_GetURLW, + DirectPlay8Address_GetURLA, + DirectPlay8Address_GetSP, + DirectPlay8Address_GetUserData, + DirectPlay8Address_SetSP, + DirectPlay8Address_SetUserData, + DirectPlay8Address_GetNumComponents, + DirectPlay8Address_GetComponentByName, + DirectPlay8Address_GetComponentByIndex, + DirectPlay8Address_AddComponent, + DirectPlay8Address_GetDevice, + DirectPlay8Address_SetDevice, + (void*)0xdead7016 /* BuildFromDirectPlay4Address */ +}; + +static ICOM_VTABLE(IDirectPlay8AddressIP) directPlay8AddressIPVT = +{ + DirectPlay8AddressIP_QueryInterface, + DirectPlay8AddressIP_AddRef, + DirectPlay8AddressIP_Release, + (void*)0xdead7024, /* BuildFromSockAddr */ + (void*)0xdead7025, /* BuildFromAddress */ + (void*)0xdead7026, /* BuildLocalAddress */ + (void*)0xdead7027, /* GetSockAddress */ + (void*)0xdead7028, /* GetLocalAddress */ + (void*)0xdead7029 /* GetAddress */ }; -HRESULT DPNET_CreateDirectPlay8Address(LPCLASSFACTORY iface, LPUNKNOWN punkOuter, REFIID riid, LPVOID *ppobj) { - IDirectPlay8AddressImpl* client; - - TRACE("(%p, %s, %p)\n", punkOuter, debugstr_guid(riid), ppobj); - - client = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectPlay8AddressImpl)); - if (NULL == client) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } - client->lpVtbl = &DirectPlay8Address_Vtbl; - client->ref = 0; /* will be inited with QueryInterface */ - return IDirectPlay8AddressImpl_QueryInterface ((PDIRECTPLAY8ADDRESS)client, riid, ppobj); -} - -/* returns name of given GUID */ -const char *debugstr_SP(const GUID *id) { - static const guid_info guids[] = { - /* CLSIDs */ - GE(CLSID_DP8SP_IPX), - GE(CLSID_DP8SP_TCPIP), - GE(CLSID_DP8SP_SERIAL), - GE(CLSID_DP8SP_MODEM) - }; - unsigned int i; - - if (!id) return "(null)"; - - for (i = 0; i < sizeof(guids)/sizeof(guids[0]); i++) { - if (IsEqualGUID(id, &guids[i].guid)) - return guids[i].name; - } - /* if we didn't find it, act like standard debugstr_guid */ - return debugstr_guid(id); +/* private functions. used by the rest of dpnet. + * Ideally should be in an interface */ +HRESULT DPNET_Address_SetSPData(PDIRECTPLAY8ADDRESS iface, void *data, + spReleaseAddressInfo spReleaseCallback, + spDuplicateAddressInfo spDuplicateCallback) +{ + ICOM_THIS(IDirectPlay8AddressImpl, iface); + + if (This->spData && This->spDataRelease) This->spDataRelease(This->spData); + This->spData = data; + This->spDataRelease = spReleaseCallback; + This->spDataDuplicate = spDuplicateCallback; + return S_OK; +} + +HRESULT DPNET_Address_GetSPData(PDIRECTPLAY8ADDRESS iface, void **data) +{ + ICOM_THIS(IDirectPlay8AddressImpl, iface); + + *data = This->spData; + return S_OK; +} + +HRESULT DPNET_Address_GetDialogLock(PDIRECTPLAY8ADDRESS iface) +{ + ICOM_THIS(IDirectPlay8AddressImpl, iface); + + if (WaitForSingleObject(This->hDialogMutex, INFINITE) != WAIT_OBJECT_0) + return E_FAIL; + return S_OK; +} + +HRESULT DPNET_Address_ReleaseDialogLock(PDIRECTPLAY8ADDRESS iface) +{ + ICOM_THIS(IDirectPlay8AddressImpl, iface); + + ReleaseMutex(This->hDialogMutex); + return S_OK; +} + +/* utility functions for parsing URLs */ + +HRESULT DPNET_GetKeyValueW(const WCHAR *url, const WCHAR *keyName, + WCHAR *keyValue /* [OUT] */, + PDWORD bufferLen /* [IN OUT] */) +{ + WCHAR *p, *p2, *p3; + DWORD requiredLen; + + TRACE("%s, %p, %s, %p (%i)\n", debugstr_w(url), keyName, + debugstr_w(keyValue), bufferLen, *bufferLen); + + p = strstrW(url, keyName); + + if (p == NULL) return DPNERR_DOESNOTEXIST; + + p = strchrW(p, DPNA_SEPARATOR_KEYVALUE); + + if (p == NULL) return DPNERR_DOESNOTEXIST; + p++; + + p2 = strchrW(p, DPNA_SEPARATOR_COMPONENT); + p3 = strchrW(p, DPNA_SEPARATOR_USERDATA); + if (p2 == NULL && p3 == NULL) /* end of string */ + requiredLen = strlenW(p); + else if (p2 == NULL) + requiredLen = p3 - p; + else if (p3 == NULL) + requiredLen = p2 - p; + else + requiredLen = (p2 < p3 ? p2 : p3) - p; + + if (*bufferLen < requiredLen) + { + *bufferLen = requiredLen; + return DPNERR_BUFFERTOOSMALL; + } + lstrcpynW(keyValue, p, requiredLen); + keyValue[requiredLen] = 0; + + return DPN_OK; +} + +static DWORD GetDataType(const WCHAR * name) +{ + int i; + + for (i = 0; i < MAX_DPNA_TYPES; i++) { + if (!strcmpW(name, dpna_types[i].name)) { + return dpna_types[i].type; + } + } + + return -1; } diff --git a/dlls/dpnet/client.c b/dlls/dpnet/client.c index 89e87e6..1e0ceba 100644 --- a/dlls/dpnet/client.c +++ b/dlls/dpnet/client.c @@ -1,7 +1,7 @@ -/* - * DirectPlay8 Client - * - * Copyright 2004 Raphael Junqueira +/* dpnet.dll + * + * Copyright (C) 2002-2007 TransGaming Inc. + * Written by: David Hammerton, Ove Kåven * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -16,252 +16,106 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - * */ -#include "config.h" - #include +#include -#define COBJMACROS #include "windef.h" #include "winbase.h" -#include "wingdi.h" #include "winuser.h" +#include "winreg.h" #include "objbase.h" #include "wine/debug.h" +#include "winerror.h" #include "dplay8.h" -#include "dpnet_private.h" +#include "dplay8_private.h" -WINE_DEFAULT_DEBUG_CHANNEL(dpnet); +WINE_DEFAULT_DEBUG_CHANNEL(dplay); -/* IDirectPlay8Client IUnknown parts follow: */ -static HRESULT WINAPI IDirectPlay8ClientImpl_QueryInterface(PDIRECTPLAY8CLIENT iface, REFIID riid, LPVOID *ppobj) -{ - IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface; +static ICOM_VTABLE(IDirectPlay8Client) directPlay8ClientVT; - if (IsEqualGUID(riid, &IID_IUnknown) - || IsEqualGUID(riid, &IID_IDirectPlay8Client)) { - IUnknown_AddRef(iface); - *ppobj = This; - return DPN_OK; +HRESULT WINAPI DirectPlay8Client_QueryInterface(PDIRECTPLAY8CLIENT iface, + REFIID riid, LPVOID *obj) +{ + ICOM_THIS(IDirectPlay8ClientImpl, iface); + TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj); + if (IsEqualGUID(&IID_IUnknown, riid) || + IsEqualGUID(&IID_IDirectPlay8Client, riid)) + { + This->ref++; + *obj = This; + return S_OK; } - - WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj); - return E_NOINTERFACE; -} - -static ULONG WINAPI IDirectPlay8ClientImpl_AddRef(PDIRECTPLAY8CLIENT iface) { - IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface; - ULONG refCount = InterlockedIncrement(&This->ref); - - TRACE("(%p)->(ref before=%u)\n", This, refCount - 1); - - return refCount; -} - -static ULONG WINAPI IDirectPlay8ClientImpl_Release(PDIRECTPLAY8CLIENT iface) { - IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface; - ULONG refCount = InterlockedDecrement(&This->ref); - - TRACE("(%p)->(ref before=%u)\n", This, refCount + 1); - - if (!refCount) { - HeapFree(GetProcessHeap(), 0, This); + else + { + FIXME("(%p)->(%s, %p): no interface\n", iface, debugstr_guid(riid), obj); + return E_NOINTERFACE; } - return refCount; -} - -/* IDirectPlay8Client Interface follow: */ - -static HRESULT WINAPI IDirectPlay8ClientImpl_Initialize(PDIRECTPLAY8CLIENT iface, PVOID CONST pvUserContext, CONST PFNDPNMESSAGEHANDLER pfn, CONST DWORD dwFlags) { - IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface; - FIXME("(%p):(%p,%p,%x): Stub\n", This, pvUserContext, pfn, dwFlags); - return DPN_OK; -} - -static HRESULT WINAPI IDirectPlay8ClientImpl_EnumServiceProviders(PDIRECTPLAY8CLIENT iface, - CONST GUID * CONST pguidServiceProvider, - CONST GUID * CONST pguidApplication, - DPN_SERVICE_PROVIDER_INFO * CONST pSPInfoBuffer, - PDWORD CONST pcbEnumData, - PDWORD CONST pcReturned, - CONST DWORD dwFlags) { - IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface; - FIXME("(%p):(%x): Stub\n", This, dwFlags); - return DPN_OK; -} - -static HRESULT WINAPI IDirectPlay8ClientImpl_EnumHosts(PDIRECTPLAY8CLIENT iface, - PDPN_APPLICATION_DESC CONST pApplicationDesc, - IDirectPlay8Address * CONST pAddrHost, - IDirectPlay8Address * CONST pDeviceInfo, - PVOID CONST pUserEnumData, CONST DWORD dwUserEnumDataSize, CONST DWORD dwEnumCount, - CONST DWORD dwRetryInterval, - CONST DWORD dwTimeOut, - PVOID CONST pvUserContext, - DPNHANDLE * CONST pAsyncHandle, - CONST DWORD dwFlags) { - IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface; - /*FIXME("(%p):(%p,%p,%p,%p,%lu,%lu,%lu,%lu): Stub\n", This, pApplicationDesc, pAddrHost, pDeviceInfo, pUserEnumData, dwUserEnumDataSize, dwEnumCount, dwRetryInterval, dwTimeOut);*/ - FIXME("(%p):(%p,%p,%x): Stub\n", This, pvUserContext, pAsyncHandle, dwFlags); - return DPN_OK; -} - -static HRESULT WINAPI IDirectPlay8ClientImpl_CancelAsyncOperation(PDIRECTPLAY8CLIENT iface, CONST DPNHANDLE hAsyncHandle, CONST DWORD dwFlags) { - IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface; - FIXME("(%p):(%u,%x): Stub\n", This, hAsyncHandle, dwFlags); - return DPN_OK; -} - -static HRESULT WINAPI IDirectPlay8ClientImpl_Connect(PDIRECTPLAY8CLIENT iface, - CONST DPN_APPLICATION_DESC * CONST pdnAppDesc, - IDirectPlay8Address * CONST pHostAddr, - IDirectPlay8Address * CONST pDeviceInfo, - CONST DPN_SECURITY_DESC * CONST pdnSecurity, - CONST DPN_SECURITY_CREDENTIALS * CONST pdnCredentials, - CONST void * CONST pvUserConnectData, - CONST DWORD dwUserConnectDataSize, - void * CONST pvAsyncContext, - DPNHANDLE * CONST phAsyncHandle, - CONST DWORD dwFlags) { - IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface; - FIXME("(%p):(%p,%p,%x): Stub\n", This, pvAsyncContext, phAsyncHandle, dwFlags); - return DPN_OK; -} - -static HRESULT WINAPI IDirectPlay8ClientImpl_Send(PDIRECTPLAY8CLIENT iface, - CONST DPN_BUFFER_DESC * CONST prgBufferDesc, - CONST DWORD cBufferDesc, - CONST DWORD dwTimeOut, - void * CONST pvAsyncContext, - DPNHANDLE * CONST phAsyncHandle, - CONST DWORD dwFlags) { - IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface; - FIXME("(%p):(%p,%p,%x): Stub\n", This, pvAsyncContext, phAsyncHandle, dwFlags); - return DPN_OK; -} - -static HRESULT WINAPI IDirectPlay8ClientImpl_GetSendQueueInfo(PDIRECTPLAY8CLIENT iface, DWORD * CONST pdwNumMsgs, DWORD * CONST pdwNumBytes, CONST DWORD dwFlags) { - IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface; - FIXME("(%p):(%x): Stub\n", This, dwFlags); - return DPN_OK; -} - -static HRESULT WINAPI IDirectPlay8ClientImpl_GetApplicationDesc(PDIRECTPLAY8CLIENT iface, DPN_APPLICATION_DESC * CONST pAppDescBuffer, DWORD * CONST pcbDataSize, CONST DWORD dwFlags) { - IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface; - FIXME("(%p):(%x): Stub\n", This, dwFlags); - return DPN_OK; -} - -static HRESULT WINAPI IDirectPlay8ClientImpl_SetClientInfo(PDIRECTPLAY8CLIENT iface, - CONST DPN_PLAYER_INFO * CONST pdpnPlayerInfo, - PVOID CONST pvAsyncContext, - DPNHANDLE * CONST phAsyncHandle, - CONST DWORD dwFlags) { - IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface; - FIXME("(%p):(%p,%p,%x): Stub\n", This, pvAsyncContext, phAsyncHandle, dwFlags); - return DPN_OK; -} - -static HRESULT WINAPI IDirectPlay8ClientImpl_GetServerInfo(PDIRECTPLAY8CLIENT iface, DPN_PLAYER_INFO * CONST pdpnPlayerInfo, DWORD * CONST pdwSize, CONST DWORD dwFlags) { - IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface; - FIXME("(%p):(%x): Stub\n", This, dwFlags); - return DPN_OK; -} - -static HRESULT WINAPI IDirectPlay8ClientImpl_GetServerAddress(PDIRECTPLAY8CLIENT iface, IDirectPlay8Address ** CONST pAddress, CONST DWORD dwFlags) { - IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface; - FIXME("(%p):(%x): Stub\n", This, dwFlags); - return DPN_OK; -} - -static HRESULT WINAPI IDirectPlay8ClientImpl_Close(PDIRECTPLAY8CLIENT iface, CONST DWORD dwFlags) { - IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface; - FIXME("(%p):(%x): Stub\n", This, dwFlags); - return DPN_OK; } -static HRESULT WINAPI IDirectPlay8ClientImpl_ReturnBuffer(PDIRECTPLAY8CLIENT iface, CONST DPNHANDLE hBufferHandle, CONST DWORD dwFlags) { - IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface; - FIXME("(%p):(%x): Stub\n", This, dwFlags); - return DPN_OK; -} - -static HRESULT WINAPI IDirectPlay8ClientImpl_GetCaps(PDIRECTPLAY8CLIENT iface, DPN_CAPS * CONST pdpCaps, CONST DWORD dwFlags) { - IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface; - FIXME("(%p):(%x): Stub\n", This, dwFlags); - return DPN_OK; -} - -static HRESULT WINAPI IDirectPlay8ClientImpl_SetCaps(PDIRECTPLAY8CLIENT iface, CONST DPN_CAPS * CONST pdpCaps, CONST DWORD dwFlags) { - IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface; - FIXME("(%p):(%x): Stub\n", This, dwFlags); - return DPN_OK; -} - -static HRESULT WINAPI IDirectPlay8ClientImpl_SetSPCaps(PDIRECTPLAY8CLIENT iface, CONST GUID * CONST pguidSP, CONST DPN_SP_CAPS * CONST pdpspCaps, CONST DWORD dwFlags ) { - IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface; - FIXME("(%p):(%x): Stub\n", This, dwFlags); - return DPN_OK; +ULONG WINAPI DirectPlay8Client_AddRef(PDIRECTPLAY8CLIENT iface) +{ + ICOM_THIS(IDirectPlay8ClientImpl, iface); + TRACE("(%p)->()\n", iface); + return ++This->ref; } -static HRESULT WINAPI IDirectPlay8ClientImpl_GetSPCaps(PDIRECTPLAY8CLIENT iface, CONST GUID * CONST pguidSP, DPN_SP_CAPS * CONST pdpspCaps, CONST DWORD dwFlags) { - IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface; - FIXME("(%p):(%x): Stub\n", This, dwFlags); - return DPN_OK; -} +ULONG WINAPI DirectPlay8Client_Release(PDIRECTPLAY8CLIENT iface) +{ + ICOM_THIS(IDirectPlay8ClientImpl, iface); + TRACE("(%p)->()\n", iface); + if (--This->ref) return This->ref; -static HRESULT WINAPI IDirectPlay8ClientImpl_GetConnectionInfo(PDIRECTPLAY8CLIENT iface, DPN_CONNECTION_INFO * CONST pdpConnectionInfo, CONST DWORD dwFlags) { - IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface; - FIXME("(%p):(%x): Stub\n", This, dwFlags); - return DPN_OK; -} + FIXME("destroy this and everything\n"); -static HRESULT WINAPI IDirectPlay8ClientImpl_RegisterLobby(PDIRECTPLAY8CLIENT iface, CONST DPNHANDLE dpnHandle, struct IDirectPlay8LobbiedApplication * CONST pIDP8LobbiedApplication, CONST DWORD dwFlags) { - IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface; - FIXME("(%p):(%x): Stub\n", This, dwFlags); - return DPN_OK; + HeapFree(GetProcessHeap(), 0, This); + return 0; } -static const IDirectPlay8ClientVtbl DirectPlay8Client_Vtbl = +HRESULT DPNET_CreateDirectPlay8Client(IUnknown *pOuter, REFIID riid, LPVOID *ppobj) { - IDirectPlay8ClientImpl_QueryInterface, - IDirectPlay8ClientImpl_AddRef, - IDirectPlay8ClientImpl_Release, - IDirectPlay8ClientImpl_Initialize, - IDirectPlay8ClientImpl_EnumServiceProviders, - IDirectPlay8ClientImpl_EnumHosts, - IDirectPlay8ClientImpl_CancelAsyncOperation, - IDirectPlay8ClientImpl_Connect, - IDirectPlay8ClientImpl_Send, - IDirectPlay8ClientImpl_GetSendQueueInfo, - IDirectPlay8ClientImpl_GetApplicationDesc, - IDirectPlay8ClientImpl_SetClientInfo, - IDirectPlay8ClientImpl_GetServerInfo, - IDirectPlay8ClientImpl_GetServerAddress, - IDirectPlay8ClientImpl_Close, - IDirectPlay8ClientImpl_ReturnBuffer, - IDirectPlay8ClientImpl_GetCaps, - IDirectPlay8ClientImpl_SetCaps, - IDirectPlay8ClientImpl_SetSPCaps, - IDirectPlay8ClientImpl_GetSPCaps, - IDirectPlay8ClientImpl_GetConnectionInfo, - IDirectPlay8ClientImpl_RegisterLobby + IDirectPlay8ClientImpl *ipDP8C; + HRESULT hr; + TRACE("()\n"); + ipDP8C = (IDirectPlay8ClientImpl *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(IDirectPlay8ClientImpl)); + if (ipDP8C == NULL) return E_OUTOFMEMORY; + ICOM_VTBL(ipDP8C) = &directPlay8ClientVT; + IDirectPlay8Client_AddRef((IDirectPlay8Client *)ipDP8C); + TRACE("Created new interface: %p\n", ipDP8C); + hr = IDirectPlay8Client_QueryInterface((IDirectPlay8Client *)ipDP8C, riid, ppobj); + IDirectPlay8Client_Release((IDirectPlay8Client *)ipDP8C); + if (SUCCEEDED(hr)) + return S_OK; + else + return E_NOINTERFACE; +} + +static ICOM_VTABLE(IDirectPlay8Client) directPlay8ClientVT = +{ + DirectPlay8Client_QueryInterface, + DirectPlay8Client_AddRef, + DirectPlay8Client_Release, + (void*)0xdead3004, /* Initilize */ + (void*)0xdead3005, /* EnumServiceProviers */ + (void*)0xdead3006, /* EnumHosts */ + (void*)0xdead3007, /* CancelAsyncOperation */ + (void*)0xdead3008, /* Connect */ + (void*)0xdead3009, /* Send */ + (void*)0xdead300a, /* GetSendQueueInfo */ + (void*)0xdead300b, /* GetApplicationDesc */ + (void*)0xdead300c, /* SetClientInfo */ + (void*)0xdead300d, /* GetServerInfo */ + (void*)0xdead300e, /* GetServerAddress */ + (void*)0xdead300f, /* Close */ + (void*)0xdead3010, /* ReturnBuffer */ + (void*)0xdead3011, /* GetCaps */ + (void*)0xdead3012, /* SetCaps */ + (void*)0xdead3013, /* SetSPCaps */ + (void*)0xdead3014, /* GetSPCaps */ + (void*)0xdead3015, /* GetConnectionInfo */ + (void*)0xdead3016 /* RegisterLobby */ }; -HRESULT DPNET_CreateDirectPlay8Client(LPCLASSFACTORY iface, LPUNKNOWN punkOuter, REFIID riid, LPVOID *ppobj) { - IDirectPlay8ClientImpl* client; - - TRACE("(%p, %s, %p)\n", punkOuter, debugstr_guid(riid), ppobj); - - client = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectPlay8ClientImpl)); - if (NULL == client) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } - client->lpVtbl = &DirectPlay8Client_Vtbl; - client->ref = 0; /* will be inited with QueryInterface */ - return IDirectPlay8ClientImpl_QueryInterface ((PDIRECTPLAY8CLIENT)client, riid, ppobj); -} diff --git a/dlls/dpnet/debug.c b/dlls/dpnet/debug.c new file mode 100644 index 0000000..1a8ca78 --- /dev/null +++ b/dlls/dpnet/debug.c @@ -0,0 +1,57 @@ +/* dpnet.dll + * + * Copyright (C) 2002-2007 TransGaming Inc. + * Written by: David Hammerton, Ove Kåven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "wine/debug.h" + +#include + +void debug_hexdump(void *data, unsigned long len) +{ + unsigned int i; + char *cdata = (char *)data; + char textout[16]; + + for (i = 0; i < len; i++) + { + if ((i % 8) == 0 && i) DPRINTF(" "); + if ((i % 16) == 0 && i) DPRINTF(" '%.8s' '%.8s'\n", &textout[0], &textout[8]); + textout[i % 16] = (cdata[i] && isprint(cdata[i])) ? cdata[i] : '.'; + DPRINTF("%02hhx ", cdata[i]); + } + if (i % 16) + { + unsigned int j; + for (j = 0; j < (16 - (i % 16)); j++) + { + if (((16 - (i % 16)) - j) == 8) DPRINTF(" "); + DPRINTF(".. "); + } + DPRINTF(" '"); + for (j = 0; j < (i % 16); j++) + { + DPRINTF("%c", textout[j]); + if (j == 8) DPRINTF("' '"); + } + DPRINTF("'\n"); + } + DPRINTF("\n"); + +} + diff --git a/dlls/dpnet/dialog.c b/dlls/dpnet/dialog.c new file mode 100644 index 0000000..ae37ae2 --- /dev/null +++ b/dlls/dpnet/dialog.c @@ -0,0 +1,113 @@ +/* dpnet.dll + * + * Copyright (C) 2002-2007 TransGaming Inc. + * Written by: David Hammerton, Ove Kåven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winreg.h" +#include "objbase.h" +#include "wine/debug.h" +#include "winerror.h" +#include "winnt.h" +#include "winuser.h" + +#include "dplay8.h" +#include "dpaddr.h" +#include "dplay8_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dplay); + +WCHAR *pHostNameUserInput = NULL; +HANDLE hHostNameUserInputMutex; +HINSTANCE hinstDpnet; + +HRESULT DPNET_HostNameDialogInit(HINSTANCE hinstDLL) +{ + pHostNameUserInput = NULL; + hinstDpnet = hinstDLL; + hHostNameUserInputMutex = CreateMutexA(NULL, FALSE, "DPNET HostNameUserInputMutex"); + return TRUE; +} + +HRESULT DPNET_HostNameDialogUninit() +{ + CloseHandle(hHostNameUserInputMutex); + return TRUE; +} + +BOOL WINAPI DPNET_HostNameDlgProc(HWND hwnd, UINT msg, WPARAM wParam, + LPARAM lParam) +{ + switch (msg) + { + case WM_COMMAND: + switch LOWORD(wParam) + { + case IDOK: + { + int textlen; + textlen = GetWindowTextLengthW(GetDlgItem(hwnd, 701)) + 1; + pHostNameUserInput = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * textlen); + GetWindowTextW(GetDlgItem(hwnd, 701), pHostNameUserInput, + textlen); + EndDialog(hwnd, wParam); + return TRUE; + } + case IDCANCEL: + EndDialog(hwnd, wParam); + return TRUE; + } + } + return FALSE; +} + +/* FIXME: maybe we should return a DirectPlay8Address ? */ +HRESULT DPNET_HostNameShowDialog(PWCHAR *ppUserInput) +{ + int hostnamebytelen; + HINSTANCE hinstDpnet2 = LoadLibraryA("DPNET"); + + TRACE("(%p)\n", ppUserInput); + + WaitForSingleObject(hHostNameUserInputMutex, INFINITE); + DialogBoxA(hinstDpnet2, "HOSTNAME", 0, DPNET_HostNameDlgProc); + + if (!pHostNameUserInput && !lstrlenW(pHostNameUserInput)) + { + TRACE("returning fail\n"); + return E_FAIL; + } + hostnamebytelen = (lstrlenW(pHostNameUserInput)+1) * sizeof(WCHAR); + *ppUserInput = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, hostnamebytelen); + memcpy(*ppUserInput, pHostNameUserInput, hostnamebytelen); + HeapFree(GetProcessHeap(), 0, pHostNameUserInput); + + ReleaseMutex(hHostNameUserInputMutex); + return S_OK; +} + +HRESULT DPNET_HostNameFree(PWCHAR pUserInput) +{ + HeapFree(GetProcessHeap(), 0, pUserInput); + return S_OK; +} + diff --git a/dlls/dpnet/dplay8_private.h b/dlls/dpnet/dplay8_private.h new file mode 100644 index 0000000..d6b3785 --- /dev/null +++ b/dlls/dpnet/dplay8_private.h @@ -0,0 +1,453 @@ +/* dpnet.dll + * + * Copyright (C) 2002-2007 TransGaming Inc. + * Written by: David Hammerton, Ove Kåven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_DPLAY8_PRIVATE_H +#define __WINE_DPLAY8_PRIVATE_H + +#include "dplay8.h" +#include "dplobby8.h" +#include "dplay8sp.h" + +#include "winsock2.h" + +#define ICOM_THIS(impl,iface) impl* const This=(impl*)(iface) +#define ICOM_VTABLE(iface) iface##Vtbl +#define ICOM_VFIELD(iface) ICOM_VTABLE(iface)* lpVtbl +#define ICOM_VTBL(iface) (iface)->lpVtbl +#define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field)) + + +typedef struct IDirectPlay8ClientImpl IDirectPlay8ClientImpl; +typedef struct IDirectPlay8PeerImpl IDirectPlay8PeerImpl; +typedef struct IDirectPlay8ServerImpl IDirectPlay8ServerImpl; +typedef struct IDirectPlay8LobbiedApplicationImpl IDirectPlay8LobbiedApplicationImpl; +typedef struct IDirectPlay8LobbyClientImpl IDirectPlay8LobbyClientImpl; +typedef struct IDirectPlay8AddressImpl IDirectPlay8AddressImpl; + +typedef struct IDirectPlay8ThreadPoolImpl IDirectPlay8ThreadPoolImpl; +typedef struct IDirectPlay8SP_TCPImpl IDirectPlay8SP_TCPImpl; +typedef struct IDirectPlay8SP_TCPIPImpl IDirectPlay8SP_TCPIPImpl; + +typedef struct tpJobQueueNode tpJobQueueNode; +typedef struct dpOutMessageToAddr dpOutMessageToAddr; + +typedef struct DPNET_AsyncOp DPNET_AsyncOp; + +/* FIXME: add some "pre-send", "retry", "timeout", "complete", + * etc, callbacks to this structure. Also we'll need a way + * to handle multiple destinations. */ + +struct DPNET_AsyncOp { + DPNET_AsyncOp *prev, *next; + DWORD dwType, dwFlags, dwID; + PVOID pvUserContext; + HANDLE hSyncEvent; + BOOL forget; + + IDirectPlay8Address *pAddrHost; + IDirectPlay8Address *pAddrDev; + DWORD dwRetryLimit, dwRetryInterval, dwTimeOut; + DWORD dwTimeSent; + DWORD cUserBuffer; + DPN_BUFFER_DESC PackBuffer; + DPN_BUFFER_DESC UserBuffer[8]; +}; + +typedef struct dpPlayer dpPlayer; + +typedef enum { + PLAYER_UNKNOWN, + PLAYER_REQUEST_SENT, + PLAYER_RESPONSE_SENT, + PLAYER_CONNECTED, + PLAYER_ACCEPTED, + PLAYER_REJECTED, + PLAYER_ACTIVE, +} PlayerStatus; + +struct dpPlayer +{ + dpPlayer *prev; /* only for remote players */ + dpPlayer *next; /* ditto */ + + BOOL set; + PlayerStatus status; + PVOID pvPlayerContext; + + DPNID dwPlayerID; + IDirectPlay8Address *pAddress; + DWORD conn_id; + DWORD ver; + DWORD dplay_ver; + + LPWSTR name; + PVOID data; + DWORD data_len; + + BYTE next_in, next_out, ack_in, ack_out; + + /* hopefully one critical section per player is OK */ + CRITICAL_SECTION cs; + + PVOID conn_data; + DWORD conn_data_len; + PVOID conn_data_ctx; + + PVOID reply_data; + DWORD reply_data_len; +}; + +struct DirectPlay8GlobalData +{ + PFNDPNMESSAGEHANDLER pfMessageHandler; + PVOID pvUserContext; + + dpOutMessageToAddr *msgToAddrTail; + DPN_CAPS dpnCaps; + + /* current service provider list */ + DPN_SERVICE_PROVIDER_INFO *pSPAvailable; + DWORD SPAvailableCount; + + /* selected service provider */ + GUID guidSP; + IDirectPlay8ServiceProvider *sp; + + BYTE dwPacketCount; + + dpPlayer localPlayer; + dpPlayer *remotePlayers; + dpPlayer *remoteHost; + CRITICAL_SECTION cs_player; + + DPN_APPLICATION_DESC appdesc; + + BOOL is_host; + LONG pkt_id; + LONG player_id; + + CRITICAL_SECTION cs_aop; + DPNET_AsyncOp *aop_head; + DPNET_AsyncOp *aop_tail; +}; + +struct IDirectPlay8ClientImpl +{ + /* IUnknown fields */ + const IDirectPlay8ClientVtbl *lpVtbl; + DWORD ref; + /* IDirectPlay8Client fields */ + void *dummy; +}; + +struct IDirectPlay8PeerImpl +{ + /* IUnknown fields */ + const IDirectPlay8PeerVtbl *lpVtbl; + DWORD ref; + /* IDirectPlay8Peer fields */ + BOOL connected; + IDirectPlay8Address *pHostAddr; + DirectPlay8GlobalData dp8gdData; +}; + +struct IDirectPlay8ServerImpl +{ + /* IUnknown fields */ + const IDirectPlay8ServerVtbl *lpVtbl; + DWORD ref; + /* IDirectPlay8Server fields */ + void *dummy; +}; + +struct IDirectPlay8LobbiedApplicationImpl +{ + /* IUnknown fields */ + const IDirectPlay8LobbiedApplicationVtbl *lpVtbl; + DWORD ref; + /* IDirectPlay8LobbiedApplicationImpl fields */ + void *dummy; +}; + +struct IDirectPlay8LobbyClientImpl +{ + /* IUnknown fields */ + const IDirectPlay8LobbyClientVtbl *lpVtbl; + DWORD ref; + /* IDirectPlay8LobbyClientImpl fields */ + void *dummy; +}; + +struct AddressComponent +{ + WCHAR *pwszName; + void *lpvData; + DWORD dwDataSize; + DWORD dwDataType; + struct AddressComponent *next; +}; + +/* a bit hacky. should be in some interface */ +typedef void (*spReleaseAddressInfo)(PVOID); +/* shouldn't need to duplicate !!!! SHOULD USE URL. HACK */ +typedef void (*spDuplicateAddressInfo)(IDirectPlay8Address *, PVOID); + +struct IDirectPlay8AddressImpl +{ + /* IUnknown fields */ + const IDirectPlay8AddressVtbl *lpVtbl; + const IDirectPlay8AddressIPVtbl *lpVtbl2; + DWORD ref; + /* IDriectPlay8Address / IDirectPlay8AddressIP fields */ + GUID guidSP; + GUID guidDevice; + + struct AddressComponent *component; + void *pvUserData; + DWORD dwDataSize; + + HANDLE hDialogMutex; /* HACK: if we are sending to this address and the + * service provider wants to show a dialogbox, it needs to + * lock this - ensures that we don't show multiple dialog boxs + * at once etc. + * This can go once sending is windowed and in a single thread. + */ + spReleaseAddressInfo spDataRelease; + spDuplicateAddressInfo spDataDuplicate; + void *spData; +}; + +typedef struct tpReadNode tpReadNode; + +typedef BOOL (*tpInitFunc)(void *, tpReadNode *); +typedef BOOL (*tpReadFunc)(void *, tpReadNode *); + +struct tpReadNode { + tpReadNode *prev; + tpReadNode *next; + + LPVOID ctx; + tpInitFunc pfnInit; + tpReadFunc pfnRead; + OVERLAPPED ovl; + DPN_BUFFER_DESC Addr; + DPN_BUFFER_DESC Data; + IDirectPlay8Address *pAddr; +}; + +typedef struct tpWriteNode tpWriteNode; + +typedef BOOL (*tpWriteFunc)(void *, tpWriteNode *); +typedef BOOL (*tpTimeFunc)(void *, tpWriteNode *); + +struct tpWriteNode { + tpWriteNode *prev; + tpWriteNode *next; + + LPVOID ctx; + tpWriteFunc pfnWrite; + tpTimeFunc pfnTime; + DPNET_AsyncOp *aop; +}; + +typedef struct tpThreadNode tpThreadNode; + +struct tpThreadNode { + tpThreadNode *prev; + tpThreadNode *next; + + HANDLE hThread, hJob; + DWORD dwID; + + CRITICAL_SECTION cs; + BOOL die_please; + tpReadNode *Read; +}; + +struct IDirectPlay8ThreadPoolImpl +{ + /* IUnknown fields */ + const IDirectPlay8ThreadPoolVtbl *lpVtbl; + DWORD ref; + + /* IDirectPlay8ThreadPool fields */ + PVOID pvUserContext; + PFNDPNMESSAGEHANDLER pfn; + DWORD dwNumThreads, dwCurThreads; + CRITICAL_SECTION cs_thread; + tpThreadNode *threads; + + HANDLE hTimer; + LARGE_INTEGER liDueTime; + CRITICAL_SECTION cs_timer; +}; + +struct IDirectPlay8SP_TCPIPImpl +{ + /* IUnknown fields */ + const IDirectPlay8ServiceProviderVtbl *lpVtbl; + DWORD ref; + /* IDirectPlay8SPWinsockTCPIP fields */ + SOCKET socket; + DWORD dwMaxSize; + IDirectPlay8ThreadPool *threadPool; + DirectPlay8GlobalData *dp8gdData; + spMessageReceived msgCallback; + DPN_SP_CAPS dpnSPCaps; +}; + +/* client.c */ +HRESULT DPNET_CreateDirectPlay8Client(IUnknown *pOuter, REFIID riid, LPVOID *ppobj); + +/* peer.c */ +HRESULT DPNET_CreateDirectPlay8Peer(IUnknown *pOuter, REFIID riid, LPVOID *ppobj); + +/* server.c */ +HRESULT DPNET_CreateDirectPlay8Server(IUnknown *pOuter, REFIID riid, LPVOID *ppobj); + +/* lobbiedapp.c */ +HRESULT DPNET_CreateDirectPlay8LobbiedApplication(IUnknown *pOuter, REFIID riid, LPVOID *ppobj); + +/* lobbyclient.c */ +HRESULT DPNET_CreateDirectPlay8LobbyClient(IUnknown *pOuter, REFIID riid, LPVOID *ppobj); + +/* address.c */ +HRESULT DPNET_CreateDirectPlay8Address(IUnknown *pOuter, REFIID riid, LPVOID *ppobj); +HRESULT DPNET_Address_SetSPData(PDIRECTPLAY8ADDRESS iface, void *data, + spReleaseAddressInfo spReleaseCallback, + spDuplicateAddressInfo spDuplicateCallback); +HRESULT DPNET_Address_GetSPData(PDIRECTPLAY8ADDRESS iface, void **data); +HRESULT DPNET_Address_GetDialogLock(PDIRECTPLAY8ADDRESS iface); +HRESULT DPNET_Address_ReleaseDialogLock(PDIRECTPLAY8ADDRESS iface); + +HRESULT DPNET_GetKeyValueW(const WCHAR *url, const WCHAR *keyName, + WCHAR *keyValue /* [OUT] */, + PDWORD bufferLen /* [IN OUT] */); + +/* sp_tcpip.c */ +HRESULT DPNET_CreateDirectPlay8SP_TCPIP(IUnknown *pOuter, REFIID riid, LPVOID *ppobj); + +/* threadpool.c */ +HRESULT DPNET_CreateDirectPlay8ThreadPool(IUnknown *pOuter, REFIID riid, LPVOID *ppobj); +HRESULT DPNET_GetThreadPool(IDirectPlay8ThreadPool **ppThreadPool, DWORD dwNumThreads); +void DPNET_InitAsyncRead(IDirectPlay8ThreadPool *pThreadPool, tpInitFunc pfnInit, tpReadFunc pfnRead, void *data); + +/* general.c */ +WCHAR *DPNET_strndupW(WCHAR *pwszSource, int len); +WCHAR *DPNET_strdupW(WCHAR *pwszSource); +DPNET_AsyncOp* DPNET_AsyncAlloc(DirectPlay8GlobalData *dp8gdData, DWORD dwType, DWORD dwSize); +HRESULT DPNET_AsyncFree(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop); +void DPNET_AsyncSetSync(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop); +void DPNET_AsyncSignal(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop); +void DPNET_AsyncWait(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop); +void DPNET_AsyncInsert(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop); +void DPNET_AsyncRemove(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop); +DPNET_AsyncOp* DPNET_AsyncSearch(DirectPlay8GlobalData *dp8gdData, DWORD dwType, DWORD dwID); +HRESULT DPNET_ObjInit(DirectPlay8GlobalData *dp8gdData, PVOID const pvUserContext, + const PFNDPNMESSAGEHANDLER pfn, const DWORD dwFlags); +void DPNET_ObjFree(DirectPlay8GlobalData *dp8gdData); +DWORD DPNET_Random(DirectPlay8GlobalData *dp8gdData); +HRESULT DPNET_EnumServiceProviders(DirectPlay8GlobalData *dp8gdData, + const GUID *const pguidServiceProvider, + const GUID *const pguidApplication, + DPN_SERVICE_PROVIDER_INFO *pSPInfoBuffer, + DWORD *pcbEnumData, + DWORD *pcReturned, + DWORD dwFlags); + +/* session.c */ +void DPNET_KillPlayers(DirectPlay8GlobalData *dp8gdData); +HRESULT DPNET_GetCaps(DirectPlay8GlobalData *dp8gdData, + DPN_CAPS *const pdpCaps, + const DWORD dwFlags); +HRESULT DPNET_GetSPCaps(DirectPlay8GlobalData *dp8gdData, + const GUID *const pguidSP, + DPN_SP_CAPS *const pdpnSPCaps, + const DWORD dwFlags); +HRESULT DPNET_CancelAsyncOperation(DirectPlay8GlobalData *dp8gdData, + const DPNHANDLE hAsyncHandle, + const DWORD dwFlags); +HRESULT DPNET_ReturnBuffer(DirectPlay8GlobalData *dp8gdData, + const DPNHANDLE hBufferHandle, + const DWORD dwFlags); +HRESULT DPNET_GetApplicationDesc(DirectPlay8GlobalData *dp8gdData, + DPN_APPLICATION_DESC *const pAppDescBuffer, + DWORD *const pcbDataSize, + const DWORD dwFlags); +HRESULT DPNET_SetPeerInfo(DirectPlay8GlobalData *dp8gdData, + const DPN_PLAYER_INFO *const pdpnPlayerInfo, + PVOID const pvAsyncContext, DPNHANDLE *const phAsyncHandle, + const DWORD dwFlags); +HRESULT DPNET_GetPeerInfo(DirectPlay8GlobalData *dp8gdData, + const DPNID dpnid, + DPN_PLAYER_INFO *const pdpnPlayerInfo, + DWORD *const pdwSize, + const DWORD dwFlags); +HRESULT DPNET_GetPlayerContext(DirectPlay8GlobalData *dp8gdData, + const DPNID dpnid, + PVOID *const ppvPlayerContext, + const DWORD dwFlags); +HRESULT DPNET_EnumHosts(DirectPlay8GlobalData *dp8gdData, + PDPN_APPLICATION_DESC const pApplicationDesc, + IDirectPlay8Address *const pAddrHost, IDirectPlay8Address *const pDeviceInfo, + PVOID const pUserEnumData, const DWORD dwUserEnumDataSize, + const DWORD dwEnumCount, const DWORD dwRetryInterval, + const DWORD dwTimeOut, PVOID const pvUserContext, DPNHANDLE *const pAsyncHandle, + const DWORD dwFlags); +HRESULT DPNET_Connect(DirectPlay8GlobalData *dp8gdData, + const DPN_APPLICATION_DESC *const pdnAppDesc, + IDirectPlay8Address *pAddrHost, + IDirectPlay8Address *pDeviceInfo, + const DPN_SECURITY_DESC * const pdnSecurity, + const DPN_SECURITY_CREDENTIALS *const pdnCredentials, + const void *const pvUserConnectData, + DWORD dwUserConnectDataSize, + void *pvPlayerContext, void *pvAsyncContext, + DPNHANDLE *phAsyncHandle, DWORD dwFlags); +HRESULT DPNET_Host(DirectPlay8GlobalData *dp8gdData, + const DPN_APPLICATION_DESC *const pdnAppDesc, + IDirectPlay8Address **const prgpDeviceInfo, + const DWORD cDeviceInfo, + const DPN_SECURITY_DESC *const pdnSecurity, + const DPN_SECURITY_CREDENTIALS *const pdnCredentials, + void *pvPlayerContext, + const DWORD dwFlags); +HRESULT DPNET_SendTo(DirectPlay8GlobalData *dp8gdData, const DPNID dpnid, + const DPN_BUFFER_DESC *const pBufferDesc, const DWORD cBufferDesc, + const DWORD dwTimeOut, void *pvAsyncContext, + DPNHANDLE *const phAsyncHandle, const DWORD dwFlags); + +/* dialog.c */ +HRESULT DPNET_HostNameDialogInit(HINSTANCE hinstDLL); +HRESULT DPNET_HostNameDialogUninit(); +HRESULT DPNET_HostNameShowDialog(PWCHAR *ppUserInput); +HRESULT DPNET_HostNameFree(PWCHAR pUserInput); + + +/* debug.c */ +void debug_hexdump(void *data, unsigned long len); + +/* parse.c */ +void DPNET_StartParse(void); +void DPNET_StopParse(void); +void DPNET_ParsePacket(int proto, struct sockaddr_in *from, struct sockaddr_in *to, + const DPN_BUFFER_DESC *buf, const DWORD bufs); + +#endif diff --git a/dlls/dpnet/dplay8sp.h b/dlls/dpnet/dplay8sp.h new file mode 100644 index 0000000..f4c1c4c --- /dev/null +++ b/dlls/dpnet/dplay8sp.h @@ -0,0 +1,107 @@ +/* dpnet.dll + * + * Copyright (C) 2002-2007 TransGaming Inc. + * Written by: David Hammerton, Ove Kåven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* This is the header file for the service providers + * PLEASE NOTE: The dp8 service provider API is NOT available from Microsoft + * and they are not willing to give it to anyone. So this interface has been + * created by David Hammerton (TransGaming Technologies). So feel + * free to change it if you want. + * It is very much a work in progress! + */ + +#ifndef _WINE_DPLAY8SP_H__ +#define _WINE_DPLAY8SP_H__ + +#include "ole2.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include "dplay8.h" + +/* IID for DirectPlay8 Service Providers */ +/* {985E2C76-66BC-4d66-AD8E-ED3801F1B459} */ +DEFINE_GUID(IID_IDirectPlay8ServiceProvider, +0x985e2c76, 0x66bc, 0x4d66, 0xad, 0x8e, 0xed, 0x38, 0x1, 0xf1, 0xb4, 0x59); + +/* interface pointers */ +typedef struct IDirectPlay8ServiceProvider *PDIRECTPLAY8SERVICEPROVIDER; + +/* external types */ +typedef struct DirectPlay8GlobalData DirectPlay8GlobalData; + +/* callback functions */ +typedef BOOL (*spMessageReceived)(DirectPlay8GlobalData *, void *, int, IDirectPlay8Address *); + +/* non structure/message datatypes */ + +/* message identifiers */ + +/* constants */ + +/* Flags */ + +/* non message structures */ + +/* message callback structures */ + +/* functions */ + +/******** Interfaces *******/ + +/* IDirectPlay8ServiceProvider */ +#define INTERFACE IDirectPlay8ServiceProvider +DECLARE_INTERFACE_(IDirectPlay8ServiceProvider,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectPlay8ServiceProvider methods ***/ + STDMETHOD_(HRESULT,Initialize)(THIS_ DirectPlay8GlobalData * dp8gdData, spMessageReceived msgCallback, DWORD dwFlags) PURE; + STDMETHOD_(HRESULT,SendTo)(THIS_ IDirectPlay8Address * pAddrDest, const DPN_BUFFER_DESC * prgBufferDesc, const DWORD cBufferDesc, DWORD dwFlags) PURE; + STDMETHOD_(HRESULT,SetSPCaps)(THIS_ DPN_SP_CAPS * pdpspCaps, DWORD dwFlags) PURE; + STDMETHOD_(HRESULT,GetSPCaps)(THIS_ DPN_SP_CAPS * pdpspCaps, DWORD dwFlags) PURE; + STDMETHOD_(HRESULT,SetSPAddressData)(THIS_ IDirectPlay8Address * pAddr) PURE; + STDMETHOD_(HRESULT,BuildAddressFromSPData)(THIS_ IDirectPlay8Address * pAddr, PVOID pvSPData) PURE; + STDMETHOD_(HRESULT,ReturnBuffer)(THIS_ void * pk, DWORD dwFlags) PURE; +}; +#undef INTERFACE + + /* IUnknown methods */ +#define IDirectPlay8ServiceProvider_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectPlay8ServiceProvider_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectPlay8ServiceProvider_Release(p) (p)->lpVtbl->Release(p) + /* IDirectPlay8ServiceProvider methods */ +#define IDirectPlay8ServiceProvider_Initialize(p,a,b,c) (p)->lpVtbl->Initialize(p,a,b,c) +#define IDirectPlay8ServiceProvider_SendTo(p,a,b,c,d) (p)->lpVtbl->SendTo(p,a,b,c,d) +#define IDirectPlay8ServiceProvider_SetSPCaps(p,a,b) (p)->lpVtbl->SetSPCaps(p,a,b) +#define IDirectPlay8ServiceProvider_GetSPCaps(p,a,b) (p)->lpVtbl->GetSPCaps(p,a,b) +#define IDirectPlay8ServiceProvider_SetSPAddressData(p,a) (p)->lpVtbl->SetSPAddressData(p,a) +#define IDirectPlay8ServiceProvider_BuildAddressFromSPData(p,a,b) (p)->lpVtbl->BuildAddressFromSPData(p,a,b) +#define IDirectPlay8ServiceProvider_ReturnBuffer(p,a,b) (p)->lpVtbl->ReturnBuffer(p,a,b) + + +#ifdef __cplusplus +} +#endif + +#endif /* _WINE_DPLAY8SP_H__ */ diff --git a/dlls/dpnet/dpnet_classfactory.c b/dlls/dpnet/dpnet_classfactory.c new file mode 100644 index 0000000..be09b93 --- /dev/null +++ b/dlls/dpnet/dpnet_classfactory.c @@ -0,0 +1,174 @@ +/* dpnet.dll + * + * Copyright (C) 2002-2007 TransGaming Inc. + * Written by: David Hammerton, Ove Kåven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winreg.h" +#include "objbase.h" +#include "wine/debug.h" +#include "winerror.h" + +#include "dplay8.h" +#include "dplobby8.h" +#include "dplay8_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dplay); + +typedef struct +{ + /* IUnknown fields */ + const IClassFactoryVtbl *lpVtbl; + DWORD ref; + HRESULT (*pfnCreateInstance)(IUnknown *pOuter, REFIID riid, + LPVOID *ppobj); +} IClassFactoryImpl; + +static HRESULT WINAPI +DPCF_QueryInterface(LPCLASSFACTORY iface, REFIID riid, LPVOID *ppobj) +{ + /*ICOM_THIS(IClassFactoryImpl, iface);*/ + + FIXME("(%p)->(%s, %p): stub\n", iface, debugstr_guid(riid), ppobj); + return E_NOINTERFACE; +} + +static ULONG WINAPI DPCF_AddRef(LPCLASSFACTORY iface) +{ + ICOM_THIS(IClassFactoryImpl,iface); + return ++(This->ref); +} + +static ULONG WINAPI DPCF_Release(LPCLASSFACTORY iface) +{ + ICOM_THIS(IClassFactoryImpl,iface); + /* static class, won't be freed */ + return --(This->ref); +} + +static HRESULT WINAPI +DPCF_CreateInstance(LPCLASSFACTORY iface, + LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj) +{ + ICOM_THIS(IClassFactoryImpl,iface); + + TRACE("(%p)->(%p,%s,%p)\n",iface,pOuter,debugstr_guid(riid),ppobj); + return This->pfnCreateInstance(pOuter, riid, ppobj); +} + +static HRESULT WINAPI DPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) +{ + /*ICOM_THIS(IClassFactoryImpl,iface);*/ + FIXME("(%p)->(%d),stub!\n",iface,dolock); + return S_OK; +} + +static const IClassFactoryVtbl DPCF_Vtbl = +{ + DPCF_QueryInterface, + DPCF_AddRef, + DPCF_Release, + DPCF_CreateInstance, + DPCF_LockServer +}; + +static IClassFactoryImpl DPNET_CF_Client = {&DPCF_Vtbl, 1, DPNET_CreateDirectPlay8Client }; +static IClassFactoryImpl DPNET_CF_Server = {&DPCF_Vtbl, 1, DPNET_CreateDirectPlay8Server }; +static IClassFactoryImpl DPNET_CF_Peer = {&DPCF_Vtbl, 1, DPNET_CreateDirectPlay8Peer }; + +static IClassFactoryImpl DPNET_CF_LobbiedApplication = {&DPCF_Vtbl, 1, DPNET_CreateDirectPlay8LobbiedApplication }; +static IClassFactoryImpl DPNET_CF_LobbyClient = {&DPCF_Vtbl, 1, DPNET_CreateDirectPlay8LobbyClient }; + +static IClassFactoryImpl DPNET_CF_Address = {&DPCF_Vtbl, 1, DPNET_CreateDirectPlay8Address }; + +static IClassFactoryImpl DPNET_CF_ThreadPool = {&DPCF_Vtbl, 1, DPNET_CreateDirectPlay8ThreadPool }; + +static IClassFactoryImpl DPNET_CF_SP_TCPIP = {&DPCF_Vtbl, 1, DPNET_CreateDirectPlay8SP_TCPIP }; + +/*********************************************************************** + * DllGetClassObject (DPNET.@) + */ +HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, + LPVOID *ppv) +{ + TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); + + if (!IsEqualGUID(riid, &IID_IClassFactory) && + !IsEqualGUID(riid, &IID_IUnknown)) + { + ERR("(%s, %s, %p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); + return CLASS_E_CLASSNOTAVAILABLE; + } + + if (IsEqualGUID(rclsid, &CLSID_DirectPlay8Client)) + { + DPCF_AddRef((IClassFactory*)&DPNET_CF_Client); + *ppv = &DPNET_CF_Client; + return S_OK; + } + else if (IsEqualGUID(rclsid, &CLSID_DirectPlay8Server)) + { + DPCF_AddRef((IClassFactory*)&DPNET_CF_Server); + *ppv = &DPNET_CF_Server; + return S_OK; + } + else if (IsEqualGUID(rclsid, &CLSID_DirectPlay8Peer)) + { + DPCF_AddRef((IClassFactory*)&DPNET_CF_Peer); + *ppv = &DPNET_CF_Peer; + return S_OK; + } + else if (IsEqualGUID(rclsid, &CLSID_DirectPlay8LobbiedApplication)) + { + DPCF_AddRef((IClassFactory*)&DPNET_CF_LobbiedApplication); + *ppv = &DPNET_CF_LobbiedApplication; + return S_OK; + } + else if (IsEqualGUID(rclsid, &CLSID_DirectPlay8LobbyClient)) + { + DPCF_AddRef((IClassFactory*)&DPNET_CF_LobbyClient); + *ppv = &DPNET_CF_LobbyClient; + return S_OK; + } + else if (IsEqualGUID(rclsid, &CLSID_DirectPlay8Address)) + { + DPCF_AddRef((IClassFactory*)&DPNET_CF_Address); + *ppv = &DPNET_CF_Address; + return S_OK; + } + else if (IsEqualGUID(rclsid, &CLSID_DirectPlay8ThreadPool)) + { + DPCF_AddRef((IClassFactory*)&DPNET_CF_ThreadPool); + *ppv = &DPNET_CF_ThreadPool; + return S_OK; + } + else if (IsEqualGUID(rclsid, &CLSID_DP8SP_TCPIP)) + { + DPCF_AddRef((IClassFactory*)&DPNET_CF_SP_TCPIP); + *ppv = &DPNET_CF_SP_TCPIP; + return S_OK; + } + ERR("(%s, %s, %p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); + return CLASS_E_CLASSNOTAVAILABLE; +} + diff --git a/dlls/dpnet/dpnet_main.c b/dlls/dpnet/dpnet_main.c index 44788d4..d8e692a 100644 --- a/dlls/dpnet/dpnet_main.c +++ b/dlls/dpnet/dpnet_main.c @@ -1,7 +1,7 @@ -/* - * DirectPlay - * - * Copyright 2004 Raphael Junqueira +/* dpnet.dll + * + * Copyright (C) 2002-2007 TransGaming Inc. + * Written by: David Hammerton, Ove Kåven * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -16,139 +16,86 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - * */ -#include "config.h" #include +#include + #include "windef.h" #include "winbase.h" -#include "wingdi.h" #include "winuser.h" -#include "objbase.h" +#include "winreg.h" #include "wine/debug.h" +#include "winerror.h" #include "dplay8.h" -/* - *#include "dplobby8.h" - *#include "dplay8sp.h" - */ -#include "dpnet_private.h" +#include "dplay8_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dplay); -WINE_DEFAULT_DEBUG_CHANNEL(dpnet); +/*********************************************************************** + * DllMain [Internal] + */ -/* At process attach */ -BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpvReserved) +BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { - TRACE("%p,%x,%p\n", hInstDLL, fdwReason, lpvReserved); - if (fdwReason == DLL_PROCESS_ATTACH) { - DisableThreadLibraryCalls(hInstDLL); - } - return TRUE; + TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved); + + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + DPNET_HostNameDialogInit(hinstDLL); + DPNET_StartParse(); + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + break; + case DLL_PROCESS_DETACH: + DPNET_StopParse(); + DPNET_HostNameDialogUninit(); + break; + } + + return TRUE; } /*********************************************************************** * DirectPlay8Create (DPNET.@) + * Old and unused thesedays. */ -HRESULT WINAPI DirectPlay8Create(REFGUID lpGUID, LPVOID *ppvInt, LPUNKNOWN punkOuter) +HRESULT WINAPI DirectPlay8Create(CONST CLSID* pcIID, LPVOID* ppvInterface, IUnknown* pUnknown) { - TRACE("(%s, %p, %p): stub\n", debugstr_guid(lpGUID), ppvInt, punkOuter); + TRACE("(%s, %p, %p): stub\n", debugstr_guid(pcIID), ppvInterface, pUnknown); return S_OK; } -/******************************************************************************* - * DirectPlay ClassFactory +/*********************************************************************** + * DllCanUnloadNow (DPNET.@) */ -typedef struct +HRESULT WINAPI DllCanUnloadNow(void) { - /* IUnknown fields */ - const IClassFactoryVtbl *lpVtbl; - LONG ref; - REFCLSID rclsid; - HRESULT (*pfnCreateInstanceFactory)(LPCLASSFACTORY iface, LPUNKNOWN punkOuter, REFIID riid, LPVOID *ppobj); -} IClassFactoryImpl; - -static HRESULT WINAPI DICF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - - FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj); - return E_NOINTERFACE; -} - -static ULONG WINAPI DICF_AddRef(LPCLASSFACTORY iface) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - return InterlockedIncrement(&This->ref); -} - -static ULONG WINAPI DICF_Release(LPCLASSFACTORY iface) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - /* static class, won't be freed */ - return InterlockedDecrement(&This->ref); -} - -static HRESULT WINAPI DICF_CreateInstance(LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - - TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj); - return This->pfnCreateInstanceFactory(iface, pOuter, riid, ppobj); -} - -static HRESULT WINAPI DICF_LockServer(LPCLASSFACTORY iface,BOOL dolock) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - FIXME("(%p)->(%d),stub!\n",This,dolock); - return S_OK; + FIXME("(void): stub\n"); + return S_OK; } -static const IClassFactoryVtbl DICF_Vtbl = { - DICF_QueryInterface, - DICF_AddRef, - DICF_Release, - DICF_CreateInstance, - DICF_LockServer -}; - -static IClassFactoryImpl DPNET_CFS[] = { - { &DICF_Vtbl, 1, &CLSID_DirectPlay8Client, DPNET_CreateDirectPlay8Client }, - { &DICF_Vtbl, 1, &CLSID_DirectPlay8Server, DPNET_CreateDirectPlay8Server }, - { &DICF_Vtbl, 1, &CLSID_DirectPlay8Peer, DPNET_CreateDirectPlay8Peer }, - { &DICF_Vtbl, 1, &CLSID_DirectPlay8Address, DPNET_CreateDirectPlay8Address }, - { NULL, 0, NULL, NULL } -}; - /*********************************************************************** - * DllCanUnloadNow (DPNET.@) + * DllRegisterServer (DPNET.@) */ -HRESULT WINAPI DllCanUnloadNow(void) +HRESULT WINAPI DllRegisterServer(void) { - return S_FALSE; + FIXME("(void): stub\n"); + return S_OK; } /*********************************************************************** - * DllGetClassObject (DPNET.@) + * DllUnregisterServer (DPNET.@) */ -HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) +HRESULT WINAPI DllUnregisterServer(void) { - int i = 0; - - TRACE("(%p,%p,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); - /* - if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) { - *ppv = (LPVOID)&DPNET_CF; - IClassFactory_AddRef((IClassFactory*)*ppv); - return S_OK; - } - */ - while (NULL != DPNET_CFS[i].rclsid) { - if (IsEqualGUID(rclsid, DPNET_CFS[i].rclsid)) { - DICF_AddRef((IClassFactory*) &DPNET_CFS[i]); - *ppv = &DPNET_CFS[i]; - return S_OK; - } - ++i; - } - - FIXME("(%p,%p,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); - return CLASS_E_CLASSNOTAVAILABLE; + FIXME("(void): stub\n"); + return S_OK; } + diff --git a/dlls/dpnet/general.c b/dlls/dpnet/general.c new file mode 100644 index 0000000..7983b62 --- /dev/null +++ b/dlls/dpnet/general.c @@ -0,0 +1,291 @@ +/* dpnet.dll + * + * Copyright (C) 2002-2007 TransGaming Inc. + * Written by: David Hammerton, Ove Kåven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winreg.h" +#include "objbase.h" +#include "wine/debug.h" +#include "winerror.h" +#include "winnt.h" +#include "winreg.h" +#include "winnls.h" +#include "wine/unicode.h" + +#include "dplay8.h" +#include "dplay8_private.h" + +#define WINE_UNICODE_REWRITE + +WINE_DEFAULT_DEBUG_CHANNEL(dplay); + +/* File that holds miscilanous functions used by all main DirectPlay8 classee */ + +WCHAR *DPNET_strndupW(WCHAR *pwszSource, int len) +{ + WCHAR *pwszNewString; + + if (!pwszSource) return NULL; + if (strlenW(pwszSource) < len) + len = strlenW(pwszSource); + pwszNewString = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (len + 1) * sizeof(WCHAR)); + memcpy(pwszNewString, pwszSource, len * sizeof(WCHAR)); + pwszNewString[len] = '\0'; + return pwszNewString; +} + +WCHAR *DPNET_strdupW(WCHAR *pwszSource) +{ + return DPNET_strndupW(pwszSource, strlenW(pwszSource)); +} + +DPNET_AsyncOp* DPNET_AsyncAlloc(DirectPlay8GlobalData *dp8gdData, DWORD dwType, DWORD dwSize) +{ + DPNET_AsyncOp* aop = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DPNET_AsyncOp) + dwSize); + aop->dwType = dwType; + aop->PackBuffer.dwBufferSize = dwSize; + aop->PackBuffer.pBufferData = (LPVOID)(aop+1); + return aop; +} + +HRESULT DPNET_AsyncFree(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop) +{ +/* HRESULT ret = aop->result; */ + HRESULT ret = S_OK; + + /* sanity check */ + if (aop->prev || aop->next || + dp8gdData->aop_head == aop || + dp8gdData->aop_tail == aop) { + FIXME("aop not unlinked before free!! expect crash!!\n"); + } + + if (aop->pAddrHost) IDirectPlay8Address_Release(aop->pAddrHost); + if (aop->pAddrDev) IDirectPlay8Address_Release(aop->pAddrDev); + if (aop->hSyncEvent) CloseHandle(aop->hSyncEvent); + HeapFree(GetProcessHeap(), 0, aop); + return ret; +} + +void DPNET_AsyncSetSync(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop) +{ + aop->hSyncEvent = CreateEventA(NULL, TRUE, FALSE, NULL); +} + +void DPNET_AsyncSignal(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop) +{ + if (aop->hSyncEvent) { + SetEvent(aop->hSyncEvent); + } else { + DPNET_AsyncFree(dp8gdData, aop); + } +} + +void DPNET_AsyncWait(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop) +{ + /* if thread pool has no threads, we should call DoWork or something */ + WaitForSingleObject(aop->hSyncEvent, INFINITE); +} + +void DPNET_AsyncInsert(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop) +{ + EnterCriticalSection(&dp8gdData->cs_aop); + aop->prev = dp8gdData->aop_tail; + aop->next = NULL; + dp8gdData->aop_tail = aop; + if (!aop->prev) dp8gdData->aop_head = aop; + LeaveCriticalSection(&dp8gdData->cs_aop); +} + +void DPNET_AsyncRemove(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop) +{ + EnterCriticalSection(&dp8gdData->cs_aop); + if (aop->prev) aop->prev->next = aop->next; + else dp8gdData->aop_head = aop->next; + aop->prev = NULL; + if (aop->next) aop->next->prev = aop->prev; + else dp8gdData->aop_tail = aop->prev; + aop->next = NULL; + LeaveCriticalSection(&dp8gdData->cs_aop); +} + +DPNET_AsyncOp* DPNET_AsyncSearch(DirectPlay8GlobalData *dp8gdData, DWORD dwType, DWORD dwID) +{ + DPNET_AsyncOp *aop; + EnterCriticalSection(&dp8gdData->cs_aop); + aop = dp8gdData->aop_head; + while (aop) { + if (aop->dwType == dwType && aop->dwID == dwID) + break; + aop = aop->next; + } + LeaveCriticalSection(&dp8gdData->cs_aop); + return aop; +} + +HRESULT DPNET_ObjInit(DirectPlay8GlobalData *dp8gdData, PVOID const pvUserContext, + const PFNDPNMESSAGEHANDLER pfn, const DWORD dwFlags) +{ + dp8gdData->pfMessageHandler = pfn; + dp8gdData->pvUserContext = pvUserContext; + dp8gdData->dpnCaps.dwSize = sizeof(DPN_CAPS); + dp8gdData->dpnCaps.dwFlags = 0; + dp8gdData->dpnCaps.dwConnectTimeout = 2000; + dp8gdData->dpnCaps.dwConnectRetries = 14; + dp8gdData->dpnCaps.dwTimeoutUntilKeepAlive = 60000; + InitializeCriticalSection(&dp8gdData->cs_aop); + InitializeCriticalSection(&dp8gdData->cs_player); + InitializeCriticalSection(&dp8gdData->localPlayer.cs); + dp8gdData->localPlayer.dplay_ver = 7; + return S_OK; +} + +void DPNET_ObjFree(DirectPlay8GlobalData *dp8gdData) +{ + int i; + DPNET_AsyncOp *aop; + + TRACE("%p\n", dp8gdData); + + DPNET_KillPlayers(dp8gdData); + + for (i = 0; i < dp8gdData->SPAvailableCount; i++) + { + HeapFree(GetProcessHeap(), 0, dp8gdData->pSPAvailable[i].pwszName); + } + HeapFree(GetProcessHeap(), 0, dp8gdData->pSPAvailable); + dp8gdData->SPAvailableCount = 0; + if (dp8gdData->sp) + { + IDirectPlay8ServiceProvider_Release(dp8gdData->sp); + } + + DeleteCriticalSection(&dp8gdData->localPlayer.cs); + DeleteCriticalSection(&dp8gdData->cs_player); + + EnterCriticalSection(&dp8gdData->cs_aop); + aop = dp8gdData->aop_head; + while (aop) { + DPNET_AsyncOp *next_aop = aop->next; + DPNET_AsyncFree(dp8gdData, aop); + aop = next_aop; + } + LeaveCriticalSection(&dp8gdData->cs_aop); + DeleteCriticalSection(&dp8gdData->cs_aop); + + HeapFree(GetProcessHeap(), 0, dp8gdData); +} + +DWORD DPNET_Random(DirectPlay8GlobalData *dp8gdData) +{ + /* this is probably random enough for our purposes. */ + return GetTickCount() * 524287; +} + +HRESULT DPNET_EnumServiceProviders(DirectPlay8GlobalData *dp8gdData, + const GUID *const pguidServiceProvider, + const GUID *const pguidApplication, + DPN_SERVICE_PROVIDER_INFO * pSPInfoBuffer, + DWORD * pcbEnumData, + DWORD * pcReturned, + const DWORD dwFlags) +{ + TRACE("(%s, %s, %p, %p (%i), %p, 0x%08x)\n", + debugstr_guid(pguidServiceProvider), debugstr_guid(pguidApplication), + pSPInfoBuffer, pcbEnumData, *pcbEnumData, pcReturned, dwFlags); + + if (pguidServiceProvider) + { + FIXME("ignoring pguidServiceProvider\n"); + } + if (pguidApplication) + { + FIXME("ignoring pguidApplication\n"); + } + if (dwFlags && dwFlags & ~DPNENUMSERVICEPROVIDERS_ALL) + { + FIXME("unrecognised flags\n"); + } + + if (!dp8gdData->pSPAvailable) /* must fill our structure of available service providers */ + { + HKEY kDPSPRoot; + DWORD subKeys, maxSubKeyLen; + LPSTR lpSubKeyBuffer; + int i; + + RegOpenKeyA(HKEY_LOCAL_MACHINE, + "Software\\Microsoft\\DirectPlay8\\Service Providers", &kDPSPRoot); + RegQueryInfoKeyA(kDPSPRoot, NULL, NULL, NULL, &subKeys, &maxSubKeyLen, + NULL, NULL, NULL, NULL, NULL, NULL); + dp8gdData->pSPAvailable = HeapAlloc(GetProcessHeap(), 0, sizeof(DPN_SERVICE_PROVIDER_INFO) * subKeys); + dp8gdData->SPAvailableCount = subKeys; + lpSubKeyBuffer = HeapAlloc(GetProcessHeap(), 0, maxSubKeyLen + 1); + for (i = 0; i < subKeys; i++) + { + HKEY kDPSP; + DWORD RegValueSize; + LPSTR lpRegValue; + LPWSTR lpRegValueW; + int WCharNameSize; + + RegEnumKeyA(kDPSPRoot, i, lpSubKeyBuffer, maxSubKeyLen + 1); + RegOpenKeyA(kDPSPRoot, lpSubKeyBuffer, &kDPSP); + + dp8gdData->pSPAvailable[i].dwFlags = 0; + + RegQueryValueExA(kDPSP, "Friendly Name", 0, NULL, NULL, &RegValueSize); + lpRegValue = HeapAlloc(GetProcessHeap(), 0, RegValueSize); + RegQueryValueExA(kDPSP, "Friendly Name", 0, NULL, (LPBYTE)lpRegValue, &RegValueSize); + WCharNameSize = RegValueSize * sizeof(WCHAR) / sizeof(CHAR); + dp8gdData->pSPAvailable[i].pwszName = HeapAlloc(GetProcessHeap(), 0, WCharNameSize); + MultiByteToWideChar(CP_ACP, 0, lpRegValue, -1, dp8gdData->pSPAvailable[i].pwszName, + WCharNameSize); + HeapFree(GetProcessHeap(), 0, lpRegValue); + + RegQueryValueExA(kDPSP, "GUID", 0, NULL, NULL, &RegValueSize); + lpRegValue = HeapAlloc(GetProcessHeap(), 0, RegValueSize); + lpRegValueW = HeapAlloc(GetProcessHeap(), 0, RegValueSize * sizeof(WCHAR) / sizeof(CHAR)); + RegQueryValueExA(kDPSP, "GUID", 0, NULL, (LPBYTE)lpRegValue, &RegValueSize); + MultiByteToWideChar(CP_ACP, 0, lpRegValue, -1, lpRegValueW, + RegValueSize * sizeof(WCHAR) / sizeof(CHAR)); + CLSIDFromString(lpRegValueW, &dp8gdData->pSPAvailable[i].guid); + HeapFree(GetProcessHeap(), 0, lpRegValue); + HeapFree(GetProcessHeap(), 0, lpRegValueW); + + dp8gdData->pSPAvailable[i].pvReserved = 0; + dp8gdData->pSPAvailable[i].dwReserved = 0; + } + HeapFree(GetProcessHeap(), 0, lpSubKeyBuffer); + } + if (*pcbEnumData < sizeof(DPN_SERVICE_PROVIDER_INFO) * dp8gdData->SPAvailableCount) + { + *pcbEnumData = sizeof(DPN_SERVICE_PROVIDER_INFO) * dp8gdData->SPAvailableCount; + *pcReturned = 0; + return DPNERR_BUFFERTOOSMALL; + } + /* FIXME: shouldn't use memcpy :( */ + memcpy(pSPInfoBuffer, dp8gdData->pSPAvailable, sizeof(DPN_SERVICE_PROVIDER_INFO) * dp8gdData->SPAvailableCount); + *pcReturned = dp8gdData->SPAvailableCount; + return S_OK; +} diff --git a/dlls/dpnet/hostname_En.rc b/dlls/dpnet/hostname_En.rc new file mode 100755 index 0000000..7e5fab0 --- /dev/null +++ b/dlls/dpnet/hostname_En.rc @@ -0,0 +1,39 @@ +/* dpnet.dll + * + * Copyright (C) 2002-2007 TransGaming Inc. + * Written by: David Hammerton, Ove Kåven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "windef.h" +#include "winuser.h" +#include "winnls.h" + +LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT + +HOSTNAME DIALOG LOADONCALL MOVEABLE DISCARDABLE 0, 0, 192, 68 +STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_CLIPSIBLINGS | WS_VISIBLE +CAPTION "Enter host name" +FONT 8, "Helv" +{ + DEFPUSHBUTTON "OK", IDOK, 135, 7, 50, 14 + PUSHBUTTON "Cancel", IDCANCEL, 135, 24, 50, 14 + LTEXT "Enter the remote machine address:", -1, 7, 7, 114, 11 + EDITTEXT 701, 7, 48, 178, 13, ES_AUTOHSCROLL +} + +#include "version.rc" + diff --git a/dlls/dpnet/lobbiedapp.c b/dlls/dpnet/lobbiedapp.c new file mode 100644 index 0000000..1ae6f1f --- /dev/null +++ b/dlls/dpnet/lobbiedapp.c @@ -0,0 +1,132 @@ +/* dpnet.dll + * + * Copyright (C) 2002-2007 TransGaming Inc. + * Written by: David Hammerton, Ove Kåven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winreg.h" +#include "objbase.h" +#include "wine/debug.h" +#include "winerror.h" + +#include "dplay8.h" +#include "dplobby8.h" +#include "dplay8_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dplay); + +static ICOM_VTABLE(IDirectPlay8LobbiedApplication) directPlay8LobbiedApplicationVT; + +HRESULT WINAPI +DirectPlay8LobbiedApplication_QueryInterface(PDIRECTPLAY8LOBBIEDAPPLICATION iface, + REFIID riid, LPVOID *obj) +{ + ICOM_THIS(IDirectPlay8LobbiedApplicationImpl, iface); + TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj); + if (IsEqualGUID(&IID_IUnknown, riid) || + IsEqualGUID(&IID_IDirectPlay8LobbiedApplication, riid)) + { + This->ref++; + *obj = This; + return S_OK; + } + else + { + FIXME("(%p)->(%s, %p): no interface\n", iface, debugstr_guid(riid), obj); + return E_NOINTERFACE; + } +} + +ULONG WINAPI +DirectPlay8LobbiedApplication_AddRef(PDIRECTPLAY8LOBBIEDAPPLICATION iface) +{ + ICOM_THIS(IDirectPlay8LobbiedApplicationImpl, iface); + TRACE("(%p)->()\n", iface); + return ++This->ref; +} + +ULONG WINAPI +DirectPlay8LobbiedApplication_Release(PDIRECTPLAY8LOBBIEDAPPLICATION iface) +{ + ICOM_THIS(IDirectPlay8LobbiedApplicationImpl, iface); + TRACE("(%p)->()\n", iface); + if (--This->ref) return This->ref; + + FIXME("destroy this and everything\n"); + + HeapFree(GetProcessHeap(), 0, This); + return 0; +} + +HRESULT WINAPI +DirectPlay8LobbiedApplication_Initialize(PDIRECTPLAY8LOBBIEDAPPLICATION iface, + const PVOID pvUserContext, + const PFNDPNMESSAGEHANDLER pfn, + DPNHANDLE * const pdpnhConnection, + const DWORD dwFlags) +{ + /*ICOM_THIS(IDirectPlay8LobbiedApplicationImpl, iface);*/ + FIXME("(%p)->(%p, %p, %p, 0x%08x): stub. Lobbying not supported, you _may_ be able to ignore this\n", + iface, pvUserContext, + pfn, pdpnhConnection, dwFlags); + *pdpnhConnection = (DPNHANDLE)NULL; + return S_OK; +} + +HRESULT +DPNET_CreateDirectPlay8LobbiedApplication(IUnknown *pOuter, REFIID riid, LPVOID *ppobj) +{ + IDirectPlay8LobbiedApplicationImpl *ipDP8LA; + HRESULT hr; + TRACE("()\n"); + ipDP8LA = (IDirectPlay8LobbiedApplicationImpl *) + HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof(IDirectPlay8LobbiedApplicationImpl)); + if (ipDP8LA == NULL) return E_OUTOFMEMORY; + ICOM_VTBL(ipDP8LA) = &directPlay8LobbiedApplicationVT; + IDirectPlay8LobbiedApplication_AddRef((IDirectPlay8LobbiedApplication *)ipDP8LA); + TRACE("Created new interface: %p\n", ipDP8LA); + hr = IDirectPlay8LobbiedApplication_QueryInterface((IDirectPlay8LobbiedApplication *)ipDP8LA, riid, ppobj); + IDirectPlay8LobbiedApplication_Release((IDirectPlay8LobbiedApplication *)ipDP8LA); + if (SUCCEEDED(hr)) + return S_OK; + else + return E_NOINTERFACE; +} + +static ICOM_VTABLE(IDirectPlay8LobbiedApplication) directPlay8LobbiedApplicationVT = +{ + DirectPlay8LobbiedApplication_QueryInterface, + DirectPlay8LobbiedApplication_AddRef, + DirectPlay8LobbiedApplication_Release, + DirectPlay8LobbiedApplication_Initialize, + (void*)0xdead5005, /* RegisterProgram */ + (void*)0xdead5006, /* UnRegisterProgram */ + (void*)0xdead5007, /* Send */ + (void*)0xdead5008, /* SetAppAvailable */ + (void*)0xdead5009, /* UpdateStatus */ + (void*)0xdead500a, /* Close */ + (void*)0xdead500b, /* GetConnectionSettings */ + (void*)0xdead500c /* SetConnectionSettings */ +}; + diff --git a/dlls/dpnet/lobbyclient.c b/dlls/dpnet/lobbyclient.c new file mode 100644 index 0000000..7fe6eec --- /dev/null +++ b/dlls/dpnet/lobbyclient.c @@ -0,0 +1,116 @@ +/* dpnet.dll + * + * Copyright (C) 2002-2007 TransGaming Inc. + * Written by: David Hammerton, Ove Kåven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winreg.h" +#include "objbase.h" +#include "wine/debug.h" +#include "winerror.h" + +#include "dplay8.h" +#include "dplobby8.h" +#include "dplay8_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dplay); + +static ICOM_VTABLE(IDirectPlay8LobbyClient) directPlay8LobbyClientVT; + +HRESULT WINAPI +DirectPlay8LobbyClient_QueryInterface(PDIRECTPLAY8LOBBYCLIENT iface, + REFIID riid, LPVOID *obj) +{ + ICOM_THIS(IDirectPlay8LobbyClientImpl, iface); + TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj); + if (IsEqualGUID(&IID_IUnknown, riid) || + IsEqualGUID(&IID_IDirectPlay8LobbyClient, riid)) + { + This->ref++; + *obj = This; + return S_OK; + } + else + { + FIXME("(%p)->(%s, %p): no interface\n", iface, debugstr_guid(riid), obj); + return E_NOINTERFACE; + } +} + +ULONG WINAPI +DirectPlay8LobbyClient_AddRef(PDIRECTPLAY8LOBBYCLIENT iface) +{ + ICOM_THIS(IDirectPlay8LobbyClientImpl, iface); + TRACE("(%p)->()\n", iface); + return ++This->ref; +} + +ULONG WINAPI +DirectPlay8LobbyClient_Release(PDIRECTPLAY8LOBBYCLIENT iface) +{ + ICOM_THIS(IDirectPlay8LobbyClientImpl, iface); + TRACE("(%p)->()\n", iface); + if (--This->ref) return This->ref; + + FIXME("destroy this and everything\n"); + + HeapFree(GetProcessHeap(), 0, This); + return 0; +} + +HRESULT +DPNET_CreateDirectPlay8LobbyClient(IUnknown *pOuter, REFIID riid, LPVOID *ppobj) +{ + IDirectPlay8LobbyClientImpl *ipDP8LC; + HRESULT hr; + TRACE("()\n"); + ipDP8LC = (IDirectPlay8LobbyClientImpl *) + HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof(IDirectPlay8LobbyClientImpl)); + if (ipDP8LC == NULL) return E_OUTOFMEMORY; + ICOM_VTBL(ipDP8LC) = &directPlay8LobbyClientVT; + IDirectPlay8LobbyClient_AddRef((IDirectPlay8LobbyClient *)ipDP8LC); + TRACE("Created new interface: %p\n", ipDP8LC); + hr = IDirectPlay8LobbyClient_QueryInterface((IDirectPlay8LobbyClient *)ipDP8LC, riid, ppobj); + IDirectPlay8LobbyClient_Release((IDirectPlay8LobbyClient *)ipDP8LC); + if (SUCCEEDED(hr)) + return S_OK; + else + return E_NOINTERFACE; +} + +static ICOM_VTABLE(IDirectPlay8LobbyClient) directPlay8LobbyClientVT = +{ + DirectPlay8LobbyClient_QueryInterface, + DirectPlay8LobbyClient_AddRef, + DirectPlay8LobbyClient_Release, + (void*)0xdead6004, /* Initialize */ + (void*)0xdead6005, /* EnumLocalPrograms */ + (void*)0xdead6006, /* ConnectApplication */ + (void*)0xdead6007, /* Send */ + (void*)0xdead6008, /* ReleaseApplication */ + (void*)0xdead6009, /* Close */ + (void*)0xdead600a, /* GetConnectionSettings */ + (void*)0xdead600b /* SetConnectionSettings */ +}; + diff --git a/dlls/dpnet/parse.c b/dlls/dpnet/parse.c new file mode 100644 index 0000000..48d7dca --- /dev/null +++ b/dlls/dpnet/parse.c @@ -0,0 +1,152 @@ +/* dpnet.dll + * + * Copyright (C) 2002-2007 TransGaming Inc. + * Written by: David Hammerton, Ove Kåven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +#include +#include +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winreg.h" +#include "objbase.h" +#include "wine/debug.h" +#include "winerror.h" +#include "winnt.h" +#include "winreg.h" +#include "winnls.h" +#include "wine/unicode.h" + +#include "nmapi.h" +#include "dplay8.h" +#include "dplay8_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dplay); + +HMODULE hParse, hNM; +PPF_PARSERDLLINFO info; + +static HPROTOCOL WINAPI (*pCreateProtocol)(LPCSTR ProtocolName, LPENTRYPOINTS lpEntryPoints, DWORD cbEntryPoints); +static HPROTOCOL WINAPI (*pGetProtocolFromName)(LPCSTR ProtocolName); +static void WINAPI (*pParsePacket)(HPROTOCOL pprot, HPROTOCOL prot, LPVOID pkt, DWORD size, DWORD hsize); + +LPVOID dllinfo; +HPROTOCOL udp, dpsp; +CRITICAL_SECTION parse_cs; + +void DPNET_GetParseInfo(void) +{ + /* this is not necessary, I think */ +#if 0 + PARSERAUTOINSTALLINFO install_info; + + install_info = (LPVOID)GetProcAddress(hParse, "ParserAutoInstallInfo"); + info = install_info(); + TRACE("got parser info: %p\n", info); +#endif +} + +void DPNET_StartParse(void) +{ + TRACE("loading dp8parse.dll\n"); + hParse = LoadLibraryA("dp8parse.dll"); + if (!hParse) { + TRACE("- dp8parse.dll not found, protocol parsing unavailable\n"); + return; + } + hNM = LoadLibraryA("nmapi.dll"); + if (!hNM) { + FreeLibrary(hParse); + hParse = 0; + TRACE("- nmapi.dll not found, protocol parsing unavailable\n"); + return; + } + pParsePacket = (LPVOID)GetProcAddress(hNM, "wine_ParsePacket"); + if (!pParsePacket) { + FreeLibrary(hNM); + hNM = 0; + FreeLibrary(hParse); + hParse = 0; + TRACE("- not using builtin nmapi.dll, protocol parsing unavailable\n"); + return; + } + pCreateProtocol = (LPVOID)GetProcAddress(hNM, "CreateProtocol"); + pGetProtocolFromName = (LPVOID)GetProcAddress(hNM, "GetProtocolFromName"); + InitializeCriticalSection(&parse_cs); + + DPNET_GetParseInfo(); + + udp = pCreateProtocol("UDP", NULL, 0); + + dpsp = pGetProtocolFromName("DPLAYSP"); +} + +void DPNET_StopParse(void) +{ + if (!hParse) return; + DeleteCriticalSection(&parse_cs); + TRACE("unloading dp8parse.dll\n"); + FreeLibrary(hNM); + hNM = 0; + FreeLibrary(hParse); + hParse = 0; +} + +typedef struct { + WORD sport; + WORD dport; + WORD len; + WORD cksum; +} UDP; + +void DPNET_ParsePacket(int proto, struct sockaddr_in *from, struct sockaddr_in *to, + const DPN_BUFFER_DESC *buf, const DWORD bufs) +{ + UDP *hdr; + LPBYTE ptr; + DWORD c, len; + + if (!hParse) return; + + len = 0; + for (c=0; csport = from ? from->sin_port : htons(2302); + hdr->dport = to ? to->sin_port : htons(2302); + hdr->len = htons(sizeof(UDP) + len); + hdr->cksum = 0; /* not important */ + ptr = (LPBYTE)(hdr+1); + for (c=0; csport), ntohs(hdr->dport), len); + + pParsePacket(udp, dpsp, hdr, sizeof(UDP) + len, sizeof(UDP)); + + LeaveCriticalSection(&parse_cs); + + HeapFree(GetProcessHeap(), 0, hdr); +} diff --git a/dlls/dpnet/peer.c b/dlls/dpnet/peer.c index cb4b638..3d95c39 100644 --- a/dlls/dpnet/peer.c +++ b/dlls/dpnet/peer.c @@ -1,7 +1,7 @@ -/* - * DirectPlay8 Peer - * - * Copyright 2004 Raphael Junqueira +/* dpnet.dll + * + * Copyright (C) 2002-2007 TransGaming Inc. + * Written by: David Hammerton, Ove Kåven * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -16,26 +16,401 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - * */ -#include "config.h" - #include - +#include #include "windef.h" #include "winbase.h" -#include "wingdi.h" #include "winuser.h" +#include "winreg.h" #include "objbase.h" #include "wine/debug.h" +#include "winerror.h" +#include "winnt.h" #include "dplay8.h" -#include "dpnet_private.h" +#include "dplay8_private.h" + +#define WINE_UNICODE_REWRITE + +WINE_DEFAULT_DEBUG_CHANNEL(dplay); + +static ICOM_VTABLE(IDirectPlay8Peer) directPlay8PeerVT; + +HRESULT WINAPI DirectPlay8Peer_QueryInterface(PDIRECTPLAY8PEER iface, + REFIID riid, LPVOID *obj) +{ + ICOM_THIS(IDirectPlay8PeerImpl, iface); + TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj); + if (IsEqualGUID(&IID_IUnknown, riid) || + IsEqualGUID(&IID_IDirectPlay8Peer, riid)) + { + This->ref++; + *obj = This; + return S_OK; + } + else + { + FIXME("(%p)->(%s, %p): no interface\n", iface, debugstr_guid(riid), obj); + return E_NOINTERFACE; + } +} + +ULONG WINAPI DirectPlay8Peer_AddRef(PDIRECTPLAY8PEER iface) +{ + ICOM_THIS(IDirectPlay8PeerImpl, iface); + TRACE("(%p)->()\n", iface); + return ++This->ref; +} + +ULONG WINAPI DirectPlay8Peer_Release(PDIRECTPLAY8PEER iface) +{ + ICOM_THIS(IDirectPlay8PeerImpl, iface); + TRACE("(%p)->()\n", iface); + if (--This->ref) return This->ref; + + DPNET_ObjFree(&This->dp8gdData); + + HeapFree(GetProcessHeap(), 0, This); + return 0; +} + +HRESULT WINAPI DirectPlay8Peer_Initialize(PDIRECTPLAY8PEER iface, PVOID const pvUserContext, + const PFNDPNMESSAGEHANDLER pfn, const DWORD dwFlags) +{ + ICOM_THIS(IDirectPlay8PeerImpl, iface); + TRACE("(%p)->(%p, %p, 0x%08x)\n", iface, pvUserContext, pfn, dwFlags); + return DPNET_ObjInit(&This->dp8gdData, pvUserContext, pfn, dwFlags); +} + +HRESULT WINAPI DirectPlay8Peer_EnumServiceProviders(PDIRECTPLAY8PEER iface, + const GUID *const pguidServiceProvider, + const GUID *const pguidApplication, + DPN_SERVICE_PROVIDER_INFO *const pSPInfoBuffer, + DWORD *const pcbEnumData, DWORD *const pcReturned, + const DWORD dwFlags) +{ + ICOM_THIS(IDirectPlay8PeerImpl, iface); + TRACE("(%p)->(%s, %s, %p, %p (%i), %p, 0x%08x)\n", + iface, debugstr_guid(pguidServiceProvider), debugstr_guid(pguidApplication), + pSPInfoBuffer, pcbEnumData, *pcbEnumData, pcReturned, dwFlags); + return DPNET_EnumServiceProviders(&This->dp8gdData, pguidServiceProvider, pguidApplication, + pSPInfoBuffer, pcbEnumData, pcReturned, dwFlags); +} + +HRESULT WINAPI DirectPlay8Peer_GetPeerAddress(PDIRECTPLAY8PEER iface, + const DPNID dpnid, + IDirectPlay8Address **const pAddress, + const DWORD dwFlags) +{ + ICOM_THIS(IDirectPlay8PeerImpl, iface); + dpPlayer *cur; + + TRACE("(%p)->(%i, %p, %08x)\n", iface, dpnid, pAddress, dwFlags); + + cur = This->dp8gdData.remotePlayers; + + while (cur) + { + if (cur->dwPlayerID == dpnid) + { + *pAddress = cur->pAddress; + IDirectPlay8Address_AddRef(*pAddress); + return S_OK; + } + cur = cur->next; + } + + /* we don't check local player, this is correct. local player isn't checked */ + return DPNERR_INVALIDPLAYER; +} + + +HRESULT WINAPI DirectPlay8Peer_GetLocalHostAddresses(PDIRECTPLAY8PEER iface, + IDirectPlay8Address **const prgpAddress, + DWORD *const pcAddress, + const DWORD dwFlags) +{ + /*ICOM_THIS(IDirectPlay8PeerImpl, iface);*/ + FIXME("(%p)->(%p, %p, 0x%08x): semi-stub\n", iface, prgpAddress, pcAddress, dwFlags); + + return DPNERR_NOTHOST; +} + +HRESULT WINAPI DirectPlay8Peer_Close(PDIRECTPLAY8PEER iface, const DWORD dwFlags) +{ + FIXME("(%p)->(0x%08x)\n", iface, dwFlags); + return S_OK; +} + +HRESULT WINAPI DirectPlay8Peer_EnumHosts(PDIRECTPLAY8PEER iface, PDPN_APPLICATION_DESC const pApplicationDesc, + IDirectPlay8Address *const pAddrHost, IDirectPlay8Address *const pDeviceInfo, + PVOID const pUserEnumData, const DWORD dwUserEnumDataSize, + const DWORD dwEnumCount, const DWORD dwRetryInterval, + const DWORD dwTimeOut, PVOID const pvUserContext, DPNHANDLE *const pAsyncHandle, + const DWORD dwFlags) +{ + ICOM_THIS(IDirectPlay8PeerImpl, iface); + TRACE("(%p)->(%p, %p, %p, %p, %i, %i, %i, %i, %p, %p, 0x%08x)\n", iface, pApplicationDesc, pAddrHost, + pDeviceInfo, pUserEnumData, dwUserEnumDataSize, dwEnumCount, dwRetryInterval, dwTimeOut, + pvUserContext, pAsyncHandle, dwFlags); + return DPNET_EnumHosts(&This->dp8gdData, pApplicationDesc, pAddrHost, + pDeviceInfo, pUserEnumData, dwUserEnumDataSize, dwEnumCount, + dwRetryInterval, dwTimeOut, pvUserContext, pAsyncHandle, dwFlags); +} + +HRESULT WINAPI DirectPlay8Peer_CancelAsyncOperation(PDIRECTPLAY8PEER iface, const DPNHANDLE hAsyncHandle, + const DWORD dwFlags) +{ + ICOM_THIS(IDirectPlay8PeerImpl, iface); + TRACE("(%p)->(0x%08x, 0x%08x)\n", iface, hAsyncHandle, dwFlags); + return DPNET_CancelAsyncOperation(&This->dp8gdData, hAsyncHandle, dwFlags); +} + +HRESULT WINAPI DirectPlay8Peer_Connect(PDIRECTPLAY8PEER iface, + const DPN_APPLICATION_DESC *const pdnAppDesc, + IDirectPlay8Address *const pHostAddr, + IDirectPlay8Address *const pDeviceInfo, + const DPN_SECURITY_DESC *const pdnSecurity, + const DPN_SECURITY_CREDENTIALS *const pdnCredentials, + const void *const pvUserConnectData, + const DWORD dwUserConnectDataSize, + void *const pvPlayerContext, void *const pvAsyncContext, + DPNHANDLE *const phAsyncHandle, const DWORD dwFlags) +{ + ICOM_THIS(IDirectPlay8PeerImpl, iface); + + TRACE("(%p)->(%p, %p, %p, %p, %p, %p, %i, %p, %p, %p, 0x%08x)\n", iface, pdnAppDesc, + pHostAddr, pDeviceInfo, pdnSecurity, pdnCredentials, pvUserConnectData, + dwUserConnectDataSize, pvPlayerContext, pvAsyncContext, phAsyncHandle, dwFlags); + if (pdnSecurity || pdnCredentials) + FIXME("we do not yet support securtity stuff.. Either does dplay8 or 9\n"); + memcpy(&This->dp8gdData.appdesc.guidApplication, &pdnAppDesc->guidApplication, sizeof(GUID)); + memcpy(&This->dp8gdData.appdesc.guidInstance, &pdnAppDesc->guidInstance, sizeof(GUID)); -WINE_DEFAULT_DEBUG_CHANNEL(dpnet); + return DPNET_Connect(&This->dp8gdData, pdnAppDesc, pHostAddr, pDeviceInfo, + pdnSecurity, pdnCredentials, pvUserConnectData, + dwUserConnectDataSize, pvPlayerContext, pvAsyncContext, + phAsyncHandle, dwFlags); +} + +HRESULT WINAPI DirectPlay8Peer_SendTo(PDIRECTPLAY8PEER iface, const DPNID dpnid, + const DPN_BUFFER_DESC *const pBufferDesc, const DWORD cBufferDesc, + const DWORD dwTimeOut, void *const pvAsyncContext, + DPNHANDLE *const phAsyncHandle, const DWORD dwFlags) +{ + ICOM_THIS(IDirectPlay8PeerImpl, iface); + TRACE("(%p)->(%i, %p, %i, %i, %p, %p, 0x%08x)\n", iface, dpnid, pBufferDesc, cBufferDesc, + dwTimeOut, pvAsyncContext, phAsyncHandle, dwFlags); + return DPNET_SendTo(&This->dp8gdData, dpnid, pBufferDesc, cBufferDesc, + dwTimeOut, pvAsyncContext, phAsyncHandle, dwFlags); +} + +HRESULT WINAPI DirectPlay8Peer_Host(PDIRECTPLAY8PEER iface, + const DPN_APPLICATION_DESC *const pdnAppDesc, + IDirectPlay8Address **const prgpDeviceInfo, + const DWORD cDeviceInfo, + const DPN_SECURITY_DESC *const pdpSecurity, + const DPN_SECURITY_CREDENTIALS *const pdpCredentials, + VOID *const pvPlayerContext, + const DWORD dwFlags) +{ + ICOM_THIS(IDirectPlay8PeerImpl, iface); + + TRACE("(%p)->(%p, %p, %i, %p, %p, %p, 0x%08x)\n", iface, pdnAppDesc, + prgpDeviceInfo, cDeviceInfo, pdpSecurity, pdpCredentials, pvPlayerContext, + dwFlags); + if (pdpSecurity || pdpCredentials) + FIXME("we do not yet support securtity stuff.. Either does dplay8 or 9\n"); -HRESULT DPNET_CreateDirectPlay8Peer(LPCLASSFACTORY iface, LPUNKNOWN punkOuter, REFIID riid, LPVOID *ppobj) { - WARN("(%p, %s, %p): stub.\n", punkOuter, debugstr_guid(riid), ppobj); - return CLASS_E_CLASSNOTAVAILABLE; + memcpy(&This->dp8gdData.appdesc.guidApplication, &pdnAppDesc->guidApplication, sizeof(GUID)); + CoCreateGuid(&This->dp8gdData.appdesc.guidInstance); + + return DPNET_Host(&This->dp8gdData, pdnAppDesc, prgpDeviceInfo, cDeviceInfo, + pdpSecurity, pdpCredentials, pvPlayerContext, dwFlags); +} + +HRESULT WINAPI DirectPlay8Peer_GetApplicationDesc(PDIRECTPLAY8PEER iface, + DPN_APPLICATION_DESC *const pAppDescBuffer, + DWORD *const pcbDataSize, + const DWORD dwFlags) +{ + ICOM_THIS(IDirectPlay8PeerImpl, iface); + TRACE("(%p)->(%p, %p (%i), 0x%08x)\n", iface, pAppDescBuffer, + pcbDataSize, *pcbDataSize, dwFlags); + return DPNET_GetApplicationDesc(&This->dp8gdData, pAppDescBuffer, pcbDataSize, dwFlags); } + + +HRESULT WINAPI DirectPlay8Peer_EnumPlayersAndGroups(PDIRECTPLAY8PEER iface, + DPNID *const prgdpnid, + DWORD *const pcdpnid, + const DWORD dwFlags) +{ + ICOM_THIS(IDirectPlay8PeerImpl, iface); + int count; + dpPlayer *cur; + + TRACE("(%p)->(%p, %p (%08i), %08x)\n", iface, prgdpnid, pcdpnid, *pcdpnid, dwFlags); + + if (!(dwFlags & DPNENUM_PLAYERS)) + { + FIXME("only support enumeration of players\n"); + return DPNERR_INVALIDFLAGS; + } + + count = 1; /* local */ + + cur = This->dp8gdData.remotePlayers; + while (cur) + { + count++; + cur = cur->next; + } + + if (*pcdpnid < count) + { + *pcdpnid = count; + return DPNERR_BUFFERTOOSMALL; + } + + count = 0; + prgdpnid[count++] = This->dp8gdData.localPlayer.dwPlayerID; + cur = This->dp8gdData.remotePlayers; + while (cur) + { + prgdpnid[count] = cur->dwPlayerID; + count++; + cur = cur->next; + } + + return S_OK; +} + +HRESULT WINAPI DirectPlay8Peer_SetPeerInfo(PDIRECTPLAY8PEER iface, + const DPN_PLAYER_INFO *const pdpnPlayerInfo, + PVOID const pvAsyncContext, DPNHANDLE *const phAsyncHandle, + const DWORD dwFlags) +{ + ICOM_THIS(IDirectPlay8PeerImpl, iface); + TRACE("(%p)->(%p, %p, %p, 0x%08x)\n", iface, pdpnPlayerInfo, + pvAsyncContext, phAsyncHandle, dwFlags); + return DPNET_SetPeerInfo(&This->dp8gdData, pdpnPlayerInfo, pvAsyncContext, phAsyncHandle, dwFlags); +} + +HRESULT WINAPI DirectPlay8Peer_GetPeerInfo(PDIRECTPLAY8PEER iface, const DPNID dpnid, + DPN_PLAYER_INFO *const pdpnPlayerInfo, + DWORD *const pdwSize, const DWORD dwFlags) +{ + ICOM_THIS(IDirectPlay8PeerImpl, iface); + TRACE("(%p)->(%x, %p, %p (%i), 0x%08x)\n", iface, dpnid, + pdpnPlayerInfo, pdwSize, *pdwSize, dwFlags); + return DPNET_GetPeerInfo(&This->dp8gdData, dpnid, pdpnPlayerInfo, pdwSize, dwFlags); +} + +HRESULT WINAPI DirectPlay8Peer_ReturnBuffer(PDIRECTPLAY8PEER iface, const DPNHANDLE hBufferHandle, + const DWORD dwFlags) +{ + ICOM_THIS(IDirectPlay8PeerImpl, iface); + TRACE("(%p)->(%i, 0x%08x)\n", iface, hBufferHandle, dwFlags); + return DPNET_ReturnBuffer(&This->dp8gdData, hBufferHandle, dwFlags); +} + +HRESULT WINAPI DirectPlay8Peer_GetPlayerContext(PDIRECTPLAY8PEER iface, const DPNID dpnid, + PVOID *const ppvPlayerContext, const DWORD dwFlags) +{ + ICOM_THIS(IDirectPlay8PeerImpl, iface); + TRACE("(%p)->(%i, %p, 0x%08x)\n", iface, dpnid, ppvPlayerContext, dwFlags); + return DPNET_GetPlayerContext(&This->dp8gdData, dpnid, ppvPlayerContext, dwFlags); +} + +HRESULT WINAPI DirectPlay8Peer_GetCaps(PDIRECTPLAY8PEER iface, DPN_CAPS *const pdpCaps, + const DWORD dwFlags) +{ + ICOM_THIS(IDirectPlay8PeerImpl, iface); + TRACE("(%p)->(%p, 0x%08x)\n", iface, pdpCaps, dwFlags); + return DPNET_GetCaps(&This->dp8gdData, pdpCaps, dwFlags); +} + +HRESULT WINAPI DirectPlay8Peer_GetSPCaps(PDIRECTPLAY8PEER iface, const GUID *const pguidSP, + DPN_SP_CAPS *const pdpnSPCaps, + const DWORD dwFlags) +{ + ICOM_THIS(IDirectPlay8PeerImpl, iface); + TRACE("(%p)->(%s, %p, 0x%08x)\n", iface, debugstr_guid(pguidSP), + pdpnSPCaps, dwFlags); + return DPNET_GetSPCaps(&This->dp8gdData, pguidSP, pdpnSPCaps, dwFlags); +} + +HRESULT WINAPI DirectPlay8Peer_TerminateSession(PDIRECTPLAY8PEER iface, + void *const pvTerminateData, + const DWORD dwTerminateDataSize, + const DWORD dwFlags) +{ + /*ICOM_THIS(IDirectPlay8PeerImpl, iface);*/ + FIXME("(%p): stub\n", iface); + return S_OK; +} + + +HRESULT DPNET_CreateDirectPlay8Peer(IUnknown *pOuter, REFIID riid, LPVOID *ppobj) +{ + IDirectPlay8PeerImpl *ipDP8P; + HRESULT hr; + TRACE("()\n"); + ipDP8P = (IDirectPlay8PeerImpl *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(IDirectPlay8PeerImpl)); + if (ipDP8P == NULL) return E_OUTOFMEMORY; + ICOM_VTBL(ipDP8P) = &directPlay8PeerVT; + IDirectPlay8Peer_AddRef((IDirectPlay8Peer *)ipDP8P); + TRACE("Created new object: %p\n", ipDP8P); + hr = IDirectPlay8Peer_QueryInterface((IDirectPlay8Peer *)ipDP8P, riid, ppobj); + IDirectPlay8Peer_Release((IDirectPlay8Peer *)ipDP8P); + if (SUCCEEDED(hr)) + return S_OK; + else + return E_NOINTERFACE; +} + +static ICOM_VTABLE(IDirectPlay8Peer) directPlay8PeerVT = +{ + DirectPlay8Peer_QueryInterface, + DirectPlay8Peer_AddRef, + DirectPlay8Peer_Release, + DirectPlay8Peer_Initialize, + DirectPlay8Peer_EnumServiceProviders, + DirectPlay8Peer_CancelAsyncOperation, + DirectPlay8Peer_Connect, + DirectPlay8Peer_SendTo, + (void*)0xdead2009, /* GetSendQueueInfo */ + DirectPlay8Peer_Host, /* Host */ + DirectPlay8Peer_GetApplicationDesc, + (void*)0xdead200c, /* SetApplicationDesc */ + (void*)0xdead200d, /* CreateGroup */ + (void*)0xdead200e, /* DestroyGroup */ + (void*)0xdead200f, /* AddPlayerToGroup */ + (void*)0xdead2010, /* RemovePlayerFromGroup */ + (void*)0xdead2011, /* SetGroupInfo */ + (void*)0xdead2012, /* GetGroupInfo */ + DirectPlay8Peer_EnumPlayersAndGroups, + (void*)0xdead2014, /* EnumGroupMembers */ + DirectPlay8Peer_SetPeerInfo, + DirectPlay8Peer_GetPeerInfo, + DirectPlay8Peer_GetPeerAddress, + DirectPlay8Peer_GetLocalHostAddresses, + DirectPlay8Peer_Close, + DirectPlay8Peer_EnumHosts, + (void*)0xdead201b, /* DestroyPeer */ + DirectPlay8Peer_ReturnBuffer, + DirectPlay8Peer_GetPlayerContext, + (void*)0xdead201e, /* GetGroupContext */ + DirectPlay8Peer_GetCaps, + (void*)0xdead2020, /* SetCaps */ + (void*)0xdead2021, /* SetSPCaps */ + DirectPlay8Peer_GetSPCaps, + (void*)0xdead2023, /* GetConnectionInfo */ + (void*)0xdead2024, /* RegisterLobby */ + DirectPlay8Peer_TerminateSession +}; + diff --git a/dlls/dpnet/protocol.h b/dlls/dpnet/protocol.h new file mode 100644 index 0000000..c210e2f --- /dev/null +++ b/dlls/dpnet/protocol.h @@ -0,0 +1,289 @@ +/* dpnet.dll + * + * Copyright (C) 2002-2007 TransGaming Inc. + * Written by: David Hammerton, Ove Kåven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_PROTOCOL_H +#define __WINE_PROTOCOL_H + +#include "dplay8.h" +#include "dplobby8.h" + +#include "pshpack1.h" + +/* message type magic numbers */ + +#define DP8P_ENUMHOSTS 0x00 +#define DP8P_CONNECT 0x88 +#define DP8P_SETPEERINFO 0x7F +#define DP8P_MESSAGEDATA 0x37 +#define DP8P_MESSAGEDATA_UNKNOWN 0x3D +#define DP8P_MESSAGEDATA_GUARANTEED 0x3F +#define DP8P_ACK 0x80 + +/* ENUMHOSTS */ + +#define DP8P_ENUMHOSTS_SEND 0x02 +#define DP8P_ENUMHOSTS_RESPONSE 0x03 + +typedef struct dp8pmsg_EnumHostsSend +{ + BYTE protocol_magic; + BYTE enum_type; /* ENUMHOST_SEND. */ + BYTE packet_count; + BYTE unknown_03; /* 0x82 */ + BYTE unknown_04; /* 0x01 */ + GUID guidApp; +} dp8pmsg_EnumHostsSend; + +typedef struct dp8pmsg_EnumHostsResponse +{ + BYTE protocol_magic; + BYTE enum_type; /* ENUMHOST_RESPONSE. */ + BYTE packet_count; + BYTE unknown_03; /* 0x82 */ + BYTE unknown_04; /* 0x00 */ + BYTE unknown_05[7]; /* 0x00 */ + BYTE unknown_12; /* ed */ + BYTE unknown_13; /* 8f */ + BYTE unknown_14; /* f0 */ + BYTE unknown_15; /* b7 */ + DWORD unknown_16; /* 0x00 */ + DWORD max_players; + DWORD current_players; /* ?? unconfirmed */ + DWORD unknown_28; /* 0x58 */ + DWORD unknown_32; /* 0x12 */ + BYTE unknown_36[24]; /* 0x00 */ + GUID guidUnknown; + GUID guidApp; + WCHAR game_name[0]; /* null terminate wide string */ +} dp8pmsg_EnumHostsResponse; + +/* ACK */ +/* response to message data (3f): 80 06 01 00 04 [05] 00 00 76 13 D8 04 + * (3f): 80 06 01 00 02 [02] 00 00 8e a7 6c 00 ( same session as below ) ( at time = 1.751872 ) + * response to server connect (88): 80 02 01 00 02 [00] 01 00 d9 11 36 6b 81 a7 6c 00 (at time = 1.729208) + * pid - sometimes its +1, odd. hrm, just seen it as +2, gah. + * type. not really sure. (doesnt change from packet to packet) + * player id, to/from? + */ +typedef struct dp8pmsg_Ack +{ + BYTE protocol_magic; + BYTE reply_type; + BYTE unknown_03; /* 01 */ + BYTE unknown_04; /* 00 */ + BYTE unknown_05; /* player ID maybe? */ + BYTE orig_packet_count; /* packet count of the one we are replying to, kinda */ + BYTE unknown_07; + BYTE unknown_08; + BYTE data[0]; + /* so far always includes: + * DWORD time_recieved; (from GetTickCount()) at end + * has also included another DWORD in connect replies, this dword is the same + * as the one we send out in 'connect' packets */ +} dp8pmsg_Ack; + +/* CONNECT */ + +/* go 1: + connect : 88 01 00 00 02 00 01 00 41 44 fe 72 a3 c7 14 00 + sresponse : 88 02 00 00 05 00 01 00 41 44 fe 72 ea a9 10 00 + --- Server recieves DPN_MSGID_INIDCATE_CONNECT here (after response)... odd + cresponse : 80 02 01 00 02 00 01 00 41 44 fe 72 ab c7 14 00 (ack) + */ +/* go 2: + connect : 88 01 00 00 02 00 01 00 c1 61 74 00 79 b2 4c 00 + sresponse : 88 02 00 00 05 00 01 00 c1 61 74 00 9b 94 48 00 + cresponse : 80 02 01 00 02 00 01 00 c1 61 74 00 80 b2 4c 00 + */ + +typedef struct dp8pmsg_Connect +{ + BYTE protocol_magic; + BYTE connect_type; /* 01 = connect, 02 = reply && connect to non-host peers. */ + BYTE packet_count; /* if so, it resets at 0. */ + BYTE unknown_04; /* 0x00 */ + BYTE unknown_05; /* 0x02 */ + BYTE unknown_06; /* 0x00 */ + BYTE unknown_07; /* 0x01 */ + BYTE unknown_08; /* 0x00 */ + /* FIXME: this unknown below MIGHT MATTER.. if so, I need to find out why?? */ + DWORD unknown_09; /* ... */ /* probably a dword of something... */ + DWORD time_sent; /* from GetTickCount() */ +} dp8pmsg_Connect; + +/* SETPEERINFO */ + +/* + 7f 00 01 00 c1 00 ...... +00 00 04 00 00 00 02 00 00 00 50 00 00 00 10 00 ........ ..P..... +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........ +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........ +00 00 b6 5d c1 46 26 50 f5 44 95 51 f4 bd af 3b ...].F&P .D.Q...; +11 c1 36 30 6a 87 d7 ff bc 46 92 09 b4 2f 61 7b ..60j... .F.../a{ +9b e7 4d 00 61 00 72 00 69 00 73 00 69 00 61 00 ..M.a.r. i.s.i.a. +00 00 .. + +*/ +/* + 7f 00 01 02 c2 00 ........ !....... +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........ +00 00 00 00 00 00 03 00 00 00 f8 01 00 00 12 00 ........ ........ +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........ +00 00 00 00 00 00 00 00 00 00 d2 e9 04 2e c5 30 ........ .......0 +f2 42 b5 28 93 ea 11 b0 55 ab 36 30 6a 87 d7 ff .B.(.... U.60j... +bc 46 92 09 b4 2f 61 7b 9b e7|d6 e9 54 2e 05 00 .F.../a{ ....T... +00 00 00 00 00 00 03 00 00 00 00 00 00 00|d0 e9 ........ ........ +24 2e 00 00 00 00 02 01 00 00 02 00 00 00 00 00 $....... ........ -- host +00 00 06 00 00 00 ea 01 00 00 0e 00 00 00 00 00 ........ ........ +00 00 00 00 00 00 00 00 00 00 00 00 00 00|d1 e9 ........ ........ +34 2e 00 00 00 00 00 01 00 00 03 00 00 00 00 00 4....... ........ -- other player +00 00 06 00 00 00 d6 01 00 00 14 00 00 00 00 00 ........ ........ +00 00 00 00 00 00 74 01 00 00 62 00 00 00|d6 e9 ......t. ..b..... +54 2e 00 00 00 00 00 01 00 00 05 00 00 00 00 00 T....... ........ +00 00 02 00 00 00 5e 01 00 00 16 00 00 00 00 00 ......^. ........ -- us ? +00 00 00 00 00 00 fc 00 00 00 62 00 00 00|78 2d ........ ..b...x- +64 69 72 65 63 74 70 6c 61 79 3a 2f 70 72 6f 76 directpl ay:/prov +69 64 65 72 3d 25 37 42 45 42 46 45 37 42 41 30 ider=%7B EBFE7BA0 +2d 36 32 38 44 2d 31 31 44 32 2d 41 45 30 46 2d -628D-11 D2-AE0F- +30 30 36 30 39 37 42 30 31 34 31 31 25 37 44 3b 006097B0 1411%7D; -- 120 (78) is len of uri + name +68 6f 73 74 6e 61 6d 65 3d 31 39 32 2e 31 36 38 hostname =192.168 -- 98 (62) is len of uri +2e 30 2e 31 39 3b 70 6f 72 74 3d 32 33 30 32 00 .0.19;po rt=2302. +54 00 65 00 73 00 74 00 50 00 6c 00 61 00 79 00 T.e.s.t. P.l.a.y. -- 22 (16) is len of name +65 00 72 00 00 00 78 2d 64 69 72 65 63 74 70 6c e.r...x- directpl +61 79 3a 2f 70 72 6f 76 69 64 65 72 3d 25 37 42 ay:/prov ider=%7B +45 42 46 45 37 42 41 30 2d 36 32 38 44 2d 31 31 EBFE7BA0 -628D-11 +44 32 2d 41 45 30 46 2d 30 30 36 30 39 37 42 30 D2-AE0F- 006097B0 -- 118 (76) is len of uri + name +31 34 31 31 25 37 44 3b 68 6f 73 74 6e 61 6d 65 1411%7D; hostname -- 98 (62) is len of uri +3d 31 39 32 2e 31 36 38 2e 30 2e 32 37 3b 70 6f =192.168 .0.27;po +72 74 3d 32 33 30 33 00 43 00 6c 00 69 00 65 00 rt=2303. C.l.i.e. -- 20 (14) is len of name +6e 00 74 00 54 00 77 00 6f 00 00 00 43 00 6c 00 n.t.T.w. o...C.l. +69 00 65 00 6e 00 74 00 00 00 54 00 65 00 73 00 i.e.n.t. ..T.e.s. -- 14 ( e) is len of name +74 00 47 00 61 00 6d 00 65 00 00 00 t.G.a.m. e... -- 18 (12) is len of game name + +*/ +typedef struct dp8pmsg_SetPeerInfo_Local +{ + BYTE protocol_magic; + BYTE unknown_02; + BYTE packet_count; + BYTE unknown_04; /* 00 */ /* -- peer type ID? */ + DWORD unknown_05; /* 0xc1 */ + DWORD unknown_09; /* 0x04 */ + DWORD unknown_13; /* 0x02 */ + DWORD unknown_17; /* 0x50, civ3 has 0x58 - perhaps offset to name or something? */ + DWORD player_name_len; + + DWORD unknown_21; /* 00 */ + DWORD unknown_25; + DWORD unknown_29; + DWORD unknown_33; + DWORD unknown_37; /* 0x50 for civ3 */ + DWORD connect_data_len; + DWORD unknown_45; + DWORD unknown_49; + GUID guidUnknown; + GUID guidApp; + BYTE data[0]; +} dp8pmsg_SetPeerInfo_Local; + +typedef struct dp8pmsg_SetPeerInfo_Game +{ + BYTE protocol_magic; + BYTE unknown_02; + BYTE packet_count; + BYTE unknown_04; /* 02 */ /* -- peer type ID? */ + DWORD unknown_05; /* c2 */ /* also possibly peer type ID, maybe flags? */ + DWORD unknown_09; /* saw 0x78 01 00 00 when we had data, could be offset? */ + DWORD reply_data_len; + BYTE unknown_17[12]; + DWORD player_count; /* FIXME: or our player number */ + DWORD len_unknown_01; /* offset? length of something. its rather odd */ + DWORD game_name_len; + BYTE unknown_x1[24]; + GUID guidUnknown; + GUID guidApp; + DWORD unknown_x2; + DWORD our_player_number; + DWORD unknown_x4; /* 0 */ + DWORD player_count_2; /* FIXME: or our player number */ + DWORD unknown_x5; /* 0 */ + BYTE data[0]; /* dp8pmsg_part_PeerInfo_Player * number of players. + + * (uri + player name) * number of players + + * game name + */ +} dp8pmsg_SetPeerInfo_Game; + +typedef struct dp8pmsg_part_PeerInfo_Player +{ + DPNID player_id; + DWORD unknown_05; /* 0 */ + DWORD unknown_09; /* something rather interesting, indeed */ + DWORD player_number; /* player number, internal? unique in a session */ + DWORD unknown_17; /* 0 */ + DWORD unknown_21; /* 06 for other? 02 for the person recieving the message? */ + DWORD unknown_25; /* some kind of count, odd really */ + DWORD player_name_len; + DWORD unknown_33; /* 0 */ + DWORD player_data_len; + DWORD unknown_41; /* something rather high, normally */ + DWORD uri_len; +} dp8pmsg_part_PeerInfo_Player; + +typedef struct dp8pmsg_SetPeerInfo_Unknown +/* I'm not sure why this is used, I need more testing. + * I'm thinking it may be for sending "hello" to each peer? */ +{ + BYTE protocol_magic; + BYTE unknown_02; + BYTE packet_count; + BYTE unknown_04; /* 02 */ + BYTE unknown_05; /* c3 to send. c5 to recieve rejected, c6 to recieve ok */ + BYTE unknown_06; /* 00 */ + BYTE unknown_07; /* 00 */ + BYTE unknown_08; /* 00 */ +} dp8pmsg_SetPeerInfo_Unknown; + +typedef struct dp8pmsg_SetPeerInfo_Connected +{ /* probably shouldn't be called SetPeerInfo */ + BYTE protocol_magic; + BYTE unknown_02; + BYTE packet_count; + BYTE unknown_04; + DWORD unknown_05; /* c5 = rejected, c6 = accepted */ + DWORD unknown_09; /* 0x80158260 */ + DWORD unknown_13; /* 0 (sample) or 0xc (civ3 rejected) */ + DWORD data_size; /* 0 or 0x21 == length of data */ + BYTE data[0]; +} dp8pmsg_SetPeerInfo_Connected; + +/* MESSAGEDATA */ + +typedef struct dp8pmsg_MessageData +{ + BYTE protocol_magic; + BYTE unknown_02; /* 00 */ + BYTE packet_count; + BYTE unknown_04; + BYTE data[0]; +} dp8pmsg_MessageData; + +#include "poppack.h" + +#endif diff --git a/dlls/dpnet/server.c b/dlls/dpnet/server.c index 085b15f..05506bb 100644 --- a/dlls/dpnet/server.c +++ b/dlls/dpnet/server.c @@ -1,7 +1,7 @@ -/* - * DirectPlay8 Server - * - * Copyright 2004 Raphael Junqueira +/* dpnet.dll + * + * Copyright (C) 2002-2007 TransGaming Inc. + * Written by: David Hammerton, Ove Kåven * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -16,26 +16,115 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - * */ -#include "config.h" - #include - +#include #include "windef.h" #include "winbase.h" -#include "wingdi.h" #include "winuser.h" +#include "winreg.h" #include "objbase.h" #include "wine/debug.h" +#include "winerror.h" #include "dplay8.h" -#include "dpnet_private.h" +#include "dplay8_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dplay); + +static ICOM_VTABLE(IDirectPlay8Server) directPlay8ServerVT; + +HRESULT WINAPI DirectPlay8Server_QueryInterface(PDIRECTPLAY8SERVER iface, + REFIID riid, LPVOID *obj) +{ + ICOM_THIS(IDirectPlay8ServerImpl, iface); + TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj); + if (IsEqualGUID(&IID_IUnknown, riid) || + IsEqualGUID(&IID_IDirectPlay8Server, riid)) + { + This->ref++; + *obj = This; + return S_OK; + } + else + { + FIXME("(%p)->(%s, %p): no interface\n", iface, debugstr_guid(riid), obj); + return E_NOINTERFACE; + } +} -WINE_DEFAULT_DEBUG_CHANNEL(dpnet); +ULONG WINAPI DirectPlay8Server_AddRef(PDIRECTPLAY8SERVER iface) +{ + ICOM_THIS(IDirectPlay8ServerImpl, iface); + TRACE("(%p)->()\n", iface); + return ++This->ref; +} + +ULONG WINAPI DirectPlay8Server_Release(PDIRECTPLAY8SERVER iface) +{ + ICOM_THIS(IDirectPlay8ServerImpl, iface); + TRACE("(%p)->()\n", iface); + if (--This->ref) return This->ref; + + FIXME("destroy this and everything\n"); + + HeapFree(GetProcessHeap(), 0, This); + return 0; +} -HRESULT DPNET_CreateDirectPlay8Server(LPCLASSFACTORY iface, LPUNKNOWN punkOuter, REFIID riid, LPVOID *ppobj) { - WARN("(%p, %s, %p): stub.\n", punkOuter, debugstr_guid(riid), ppobj); - return CLASS_E_CLASSNOTAVAILABLE; +HRESULT DPNET_CreateDirectPlay8Server(IUnknown *pOuter, REFIID riid, LPVOID *ppobj) +{ + IDirectPlay8ServerImpl *ipDP8S; + HRESULT hr; + TRACE("()\n"); + ipDP8S = (IDirectPlay8ServerImpl *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(IDirectPlay8ServerImpl)); + if (ipDP8S == NULL) return E_OUTOFMEMORY; + ICOM_VTBL(ipDP8S) = &directPlay8ServerVT; + IDirectPlay8Server_AddRef((IDirectPlay8Server *)ipDP8S); + TRACE("Created new object: %p\n", ipDP8S); + hr = IDirectPlay8Server_QueryInterface((IDirectPlay8Server *)ipDP8S, riid, ppobj); + IDirectPlay8Server_Release((IDirectPlay8Server *)ipDP8S); + if (SUCCEEDED(hr)) + return S_OK; + else + return E_NOINTERFACE; } + +static ICOM_VTABLE(IDirectPlay8Server) directPlay8ServerVT = +{ + DirectPlay8Server_QueryInterface, + DirectPlay8Server_AddRef, + DirectPlay8Server_Release, + (void*)0xdead4004, /* Initilize */ + (void*)0xdead4005, /* EnumServiceProviers */ + (void*)0xdead4006, /* CancelAsyncOperation */ + (void*)0xdead4007, /* GetSendQueueInfo */ + (void*)0xdead4008, /* GetApplicationDesc */ + (void*)0xdead4009, /* SetServerInfo */ + (void*)0xdead400a, /* GetClientInfo */ + (void*)0xdead400b, /* GetClientAddress */ + (void*)0xdead400c, /* GetLocalHostAddresses */ + (void*)0xdead400d, /* SetApplicationDesc */ + (void*)0xdead400e, /* Host */ + (void*)0xdead400f, /* SendTo */ + (void*)0xdead4010, /* CreateGroup */ + (void*)0xdead4011, /* DestroyGroup */ + (void*)0xdead4012, /* AddPlayerToGroup */ + (void*)0xdead4013, /* RemovePlayerFromGroup */ + (void*)0xdead4014, /* SetGroupInfo */ + (void*)0xdead4015, /* GetGroupInfo */ + (void*)0xdead4016, /* EnumPlayersAndGroups */ + (void*)0xdead4017, /* Close */ + (void*)0xdead4018, /* DestroyClient */ + (void*)0xdead4019, /* ReturnBuffer */ + (void*)0xdead401a, /* GetPlayerContext */ + (void*)0xdead401b, /* GetGroupContext */ + (void*)0xdead401c, /* SetCaps */ + (void*)0xdead401d, /* GetCaps */ + (void*)0xdead401e, /* GetConnectionInfo */ + (void*)0xdead401f /* RegisterLobby */ +}; + + diff --git a/dlls/dpnet/session.c b/dlls/dpnet/session.c new file mode 100644 index 0000000..cfb11ae --- /dev/null +++ b/dlls/dpnet/session.c @@ -0,0 +1,2373 @@ +/* dpnet.dll + * + * Copyright (C) 2002-2007 TransGaming Inc. + * Written by: David Hammerton, Ove Kåven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winreg.h" +#include "objbase.h" +#include "wine/debug.h" +#include "winerror.h" +#include "winnt.h" +#include "winreg.h" +#include "winnls.h" +#include "wine/unicode.h" + +#include "dplay8.h" +#include "dplay8_private.h" + +/* DirectPlay 8 session protocol */ + +#include "pshpack1.h" + +/* some packets seem to change with the version + * first message packet: + * ver 5: 3f 00 00 00 (first packet) + * 3f 01 00 00 (retransmits) + * ver 6: 3f 02 00 00 (first packet) + * 3f 03 00 00 (retransmits) + */ +#define DP8SESS_DEFVER MAKELONG(5, 1) +#define DP8SESS_MINVER(a,b) min(a,b) + +typedef struct { + DWORD size; + DWORD flags; + DWORD max_players; + DWORD cur_players; + /* ofs 16 */ + DWORD name_ofs; + DWORD name_size; + DWORD pass_ofs; + DWORD pass_size; + /* ofs 32 */ + DWORD res_ofs; + DWORD res_size; + DWORD appres_ofs; + DWORD appres_size; + /* ofs 48 */ + GUID instGUID; + /* ofs 64 */ + GUID appGUID; + /* ofs 80 */ +} DP8_AppDesc; + +#define DP8SESS_TAG 0 +#define DP8SESS_ENUM_REQUEST 2 +#define DP8SESS_ENUM_RESPONSE 3 + +#define DP8SESS_ENUM_REQ_WITH_GUID 1 +#define DP8SESS_ENUM_REQ_WITHOUT_GUID 2 + +typedef struct { + BYTE tag; + BYTE command; + WORD id; + /* ofs 4 */ + BYTE type; +} DP8_EnumRequest; + +typedef struct { + BYTE tag; + BYTE command; + WORD id; + /* ofs 4 */ + DWORD reply_ofs; + DWORD reply_size; + /* ofs 12 */ + DP8_AppDesc app_desc; + /* ofs 92 */ +} DP8_EnumResponse; + +#define DP8SESS_PATH_TEST 5 + +typedef struct { + BYTE tag; + BYTE command; + WORD id; + /* ofs 4 */ + DWORD key1; + DWORD key2; +} DP8_PathTest; + +#define DP8SESS_CONNECT 0x88 +#define DP8SESS_CONN_REQUEST 0x01 +#define DP8SESS_CONN_RESPONSE 0x02 + +typedef struct { + BYTE command; + BYTE type; + BYTE pkt; + BYTE unknown_03; + /* ofs 4 */ + DWORD ver; + /* ofs 8 */ + DWORD id; + DWORD time; + /* ofs 16 */ +} DP8_Connect; + +#define DP8SESS_ACKNOWLEDGE 0x80 +#define DP8SESS_ACK_CONNECT 0x02 +#define DP8SESS_ACK_DATA_RELIABLE 0x06 + +typedef struct { + BYTE command; + BYTE type; + WORD unknown_02; + /* ofs 4 */ + DWORD ver; + /* ofs 8 */ + DWORD id; + DWORD time; + /* ofs 16 */ +} DP8_ConnAck; + +typedef struct { + BYTE command; + BYTE type; + WORD unknown_02; + /* ofs 4 */ + BYTE next_out; + BYTE next_in; + WORD unknown_06; + /* ofs 8 */ + DWORD time; + /* ofs 16 */ +} DP8_DataAck; + +#define DP8SESS_MESSAGE 0x7f + +typedef struct { + BYTE command; + BYTE type; + BYTE next_out; + BYTE next_in; + /* ofs 4 */ + DWORD msg; + /* ofs 8 */ +} DP8_Message; + +#define DP8SESS_MSG_PLAYER_CONNECT 0xc1 + +#define DP8SESS_CONNF_SERVER 0x01 +#define DP8SESS_CONNF_CLIENT 0x02 +#define DP8SESS_CONNF_PEER 0x04 + +typedef struct { + DP8_Message msg; + /* ofs 8 */ + DWORD flags; + DWORD dplay_ver; + DWORD name_ofs; + DWORD name_size; + DWORD data_ofs; + DWORD data_size; + DWORD pass_ofs; + DWORD pass_size; + DWORD conn_ofs; + DWORD conn_size; + DWORD url_ofs; + DWORD url_size; + GUID instGUID; + GUID appGUID; + DWORD addr_ofs; + DWORD addr_size; +} DP8_PlayerConnect; + +#define DP8SESS_MSG_SESSION_INFO 0xc2 + +typedef struct { + DP8_Message msg; + /* ofs 8 */ + DWORD reply_ofs; + DWORD reply_size; + /* ofs 16 */ + DP8_AppDesc app_desc; + /* ofs 96 */ + DWORD player_id; + DWORD ver; + DWORD unknown_104; + DWORD entries; + DWORD members; +} DP8_SessionInfo; + +#define DP8SESS_PINFOF_LOCAL 0x0001 +#define DP8SESS_PINFOF_HOST 0x0002 +#define DP8SESS_PINFOF_ALLPLAYER_GROUP 0x0004 +#define DP8SESS_PINFOF_GROUP 0x0010 +#define DP8SESS_PINFOF_MULTICAST_GROUP 0x0020 +#define DP8SESS_PINFOF_AUTODESTRUCT_GROUP 0x0040 +#define DP8SESS_PINFOF_PEER 0x0100 +#define DP8SESS_PINFOF_CLIENT 0x0200 +#define DP8SESS_PINFOF_SERVER 0x0400 +#define DP8SESS_PINFOF_AVAILABLE 0x1000 +#define DP8SESS_PINFOF_CONNECTING 0x2000 +#define DP8SESS_PINFOF_DISCONNECTING 0x4000 + +typedef struct { + DWORD group_id; + DWORD owner_id; + DWORD flags; + DWORD ver; + /* ofs 16 */ + DWORD unknown_16; + DWORD dplay_ver; + DWORD name_ofs; + DWORD name_size; + DWORD data_ofs; + DWORD data_size; + DWORD url_ofs; + DWORD url_size; +} DP8_PlayerInfo; + +#define DP8SESS_MSG_SESSION_ACK 0xc3 + +typedef struct { + DP8_Message msg; +} DP8_SessionAck; + +#define DP8SESS_MSG_PEER_CONNECT 0xc6 + +typedef struct { + DP8_Message msg; + /* ofs 8 */ + DWORD player_id; + DWORD ver; + /* ofs 16 */ + DWORD unknown_16; +} DP8_PeerConnect; + +#define DP8SESS_MSG_TABLE_VER 0xc9 + +typedef struct { + DP8_Message msg; + /* ofs 8 */ + DWORD ver; + /* ofs 12 */ + DWORD unknown_12; +} DP8_TableVer; + +#define DP8SESS_MSG_APPDESC_UPDATE 0xcf + +typedef struct { + DP8_Message msg; + /* ofs 8 */ + DP8_AppDesc app_desc; + /* ofs 88 */ +} DP8_AppDescUpdate; + +#define DP8SESS_DATA_UNRELIABLE 0x37 +#define DP8SESS_DATA_RELIABLE 0x3f + +typedef struct { + BYTE command; + BYTE type; + BYTE next_out; + BYTE next_in; + /* ofs 4 */ +} DP8_Data; + +#include "poppack.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dplay); + +static BOOL DPNET_RecvPacket(DirectPlay8GlobalData *, void *, int, IDirectPlay8Address *); +static HRESULT DPNET_StartAsync(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop); + +static HRESULT DPNET_InitSP(DirectPlay8GlobalData *dp8gdData, const GUID *const guidNewSP) +{ + if (!IsEqualGUID(guidNewSP, &dp8gdData->guidSP)) + { + HRESULT hr; + if (dp8gdData->sp) + { + IDirectPlay8ServiceProvider_Release(dp8gdData->sp); + dp8gdData->sp = NULL; + } + memcpy(&dp8gdData->guidSP, guidNewSP, sizeof(GUID)); + hr = CoCreateInstance(&dp8gdData->guidSP, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectPlay8ServiceProvider, + (LPVOID *) &dp8gdData->sp); + if (SUCCEEDED(hr)) + { + IDirectPlay8ServiceProvider_Initialize(dp8gdData->sp, dp8gdData, DPNET_RecvPacket, 0); + } + else + { + WARN("failed to switch to service provider %s\n", debugstr_guid(guidNewSP)); + memset(&dp8gdData->guidSP, 0, sizeof(GUID)); + return hr; + + } + } + return S_OK; +} + +static void DPNET_SetAppDesc(DirectPlay8GlobalData *dp8gdData, const DPN_APPLICATION_DESC *pdnAppDesc) +{ + dp8gdData->appdesc.dwMaxPlayers = max(dp8gdData->appdesc.dwCurrentPlayers, pdnAppDesc->dwMaxPlayers); + if (dp8gdData->appdesc.pwszSessionName != pdnAppDesc->pwszSessionName) { + if (dp8gdData->appdesc.pwszSessionName) + HeapFree(GetProcessHeap(), 0, dp8gdData->appdesc.pwszSessionName); + dp8gdData->appdesc.pwszSessionName = DPNET_strdupW(pdnAppDesc->pwszSessionName); + } + if (dp8gdData->appdesc.pwszPassword != pdnAppDesc->pwszPassword) { + if (dp8gdData->appdesc.pwszPassword) + HeapFree(GetProcessHeap(), 0, dp8gdData->appdesc.pwszPassword); + dp8gdData->appdesc.pwszPassword = DPNET_strdupW(pdnAppDesc->pwszPassword); + } + if (dp8gdData->appdesc.pvApplicationReservedData != pdnAppDesc->pvApplicationReservedData || + dp8gdData->appdesc.dwApplicationReservedDataSize != pdnAppDesc->dwApplicationReservedDataSize) { + if (dp8gdData->appdesc.pvApplicationReservedData) + HeapFree(GetProcessHeap(), 0, dp8gdData->appdesc.pvApplicationReservedData); + if (pdnAppDesc->pvApplicationReservedData && pdnAppDesc->dwApplicationReservedDataSize) { + dp8gdData->appdesc.pvApplicationReservedData = HeapAlloc(GetProcessHeap(), 0, pdnAppDesc->dwApplicationReservedDataSize); + dp8gdData->appdesc.dwApplicationReservedDataSize = pdnAppDesc->dwApplicationReservedDataSize; + memcpy(dp8gdData->appdesc.pvApplicationReservedData, pdnAppDesc->pvApplicationReservedData, pdnAppDesc->dwApplicationReservedDataSize); + } + else { + dp8gdData->appdesc.pvApplicationReservedData = NULL; + dp8gdData->appdesc.dwApplicationReservedDataSize = 0; + } + } +} + +static void DPNET_ReturnBufferToApp(DirectPlay8GlobalData *dp8gdData, HRESULT hr, + PVOID pvBuffer, PVOID pvUserContext) +{ + DPNMSG_RETURN_BUFFER ret; + if (!pvBuffer) return; + ret.dwSize = sizeof(ret); + ret.hResultCode = hr; + ret.pvBuffer = pvBuffer; + ret.pvUserContext = pvUserContext; + hr = dp8gdData->pfMessageHandler(dp8gdData->pvUserContext, DPN_MSGID_RETURN_BUFFER, &ret); +} + +static dpPlayer* DPNET_FindPlayerByAddr(DirectPlay8GlobalData *dp8gdData, IDirectPlay8Address *pAddress) +{ + dpPlayer *play; + EnterCriticalSection(&dp8gdData->cs_player); + /* see if the service provider already identified a player */ + play = dp8gdData->remotePlayers; + while (play) { + if (play->pAddress == pAddress) break; + play = play->next; + } + LeaveCriticalSection(&dp8gdData->cs_player); + return play; +} + +static dpPlayer* DPNET_FindPlayerByID(DirectPlay8GlobalData *dp8gdData, DPNID dpnid) +{ + dpPlayer *play; + EnterCriticalSection(&dp8gdData->cs_player); + play = &dp8gdData->localPlayer; + if (play->dwPlayerID != dpnid) { + play = dp8gdData->remotePlayers; + while (play) { + if (play->dwPlayerID == dpnid) break; + play = play->next; + } + } + LeaveCriticalSection(&dp8gdData->cs_player); + return play; +} + +static dpPlayer* DPNET_MakePlayer(DirectPlay8GlobalData *dp8gdData, IDirectPlay8Address *pAddress, BOOL *found) +{ + dpPlayer *play; + EnterCriticalSection(&dp8gdData->cs_player); + /* see if the service provider already identified a player */ + play = dp8gdData->remotePlayers; + while (play) { + if (play->pAddress == pAddress) { + *found = TRUE; + break; + } + play = play->next; + } + if (!play) { + /* create new player */ + *found = FALSE; + play = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dpPlayer)); + InitializeCriticalSection(&play->cs); + IDirectPlay8Address_Duplicate(pAddress, &play->pAddress); + play->next = dp8gdData->remotePlayers; + dp8gdData->remotePlayers = play; + } + LeaveCriticalSection(&dp8gdData->cs_player); + return play; +} + +static void DPNET_KillPlayer(DirectPlay8GlobalData *dp8gdData, dpPlayer *play) +{ + EnterCriticalSection(&dp8gdData->cs_player); + + /* free remote player */ + if (play->prev) play->prev->next = play->next; + else dp8gdData->remotePlayers = play->next; + if (play->next) play->next->prev = play->prev; + DPNET_ReturnBufferToApp(dp8gdData, S_OK, play->conn_data, play->conn_data_ctx); + if (play->reply_data) HeapFree(GetProcessHeap(), 0, play->reply_data); + if (play->pAddress) IDirectPlay8Address_Release(play->pAddress); + if (play->status == PLAYER_ACTIVE) + dp8gdData->appdesc.dwCurrentPlayers--; + DeleteCriticalSection(&play->cs); + HeapFree(GetProcessHeap(), 0, play); + + LeaveCriticalSection(&dp8gdData->cs_player); +} + +void DPNET_KillPlayers(DirectPlay8GlobalData *dp8gdData) +{ + dpPlayer *play; + EnterCriticalSection(&dp8gdData->cs_player); + + /* free remote players */ + while (dp8gdData->remotePlayers) { + play = dp8gdData->remotePlayers; + dp8gdData->remotePlayers = play->next; + if (play->next) play->next->prev = NULL; + DPNET_ReturnBufferToApp(dp8gdData, S_OK, play->conn_data, play->conn_data_ctx); + if (play->reply_data) HeapFree(GetProcessHeap(), 0, play->reply_data); + if (play->pAddress) IDirectPlay8Address_Release(play->pAddress); + DeleteCriticalSection(&play->cs); + HeapFree(GetProcessHeap(), 0, play); + } + + /* free local player */ + play = &dp8gdData->localPlayer; + play->status = PLAYER_UNKNOWN; + if (play->conn_data) { + HeapFree(GetProcessHeap(), 0, play->conn_data); + play->conn_data = NULL; + play->conn_data_len = 0; + } + if (play->pAddress) IDirectPlay8Address_Release(play->pAddress); + play->pAddress = NULL; + + dp8gdData->remoteHost = NULL; + + dp8gdData->appdesc.dwCurrentPlayers = 0; + LeaveCriticalSection(&dp8gdData->cs_player); +} + +static void DPNET_LockPlayer(DirectPlay8GlobalData *dp8gdData, dpPlayer *play) +{ + EnterCriticalSection(&play->cs); +} + +static void DPNET_UnlockPlayer(DirectPlay8GlobalData *dp8gdData, dpPlayer *play) +{ + LeaveCriticalSection(&play->cs); +} + +static BOOL DPNET_GotAck(DirectPlay8GlobalData *dp8gdData, dpPlayer *play, BYTE next_out, BYTE next_in) +{ + /* FIXME: what about wraparound, eh? */ + + if (next_in > play->next_out) { + TRACE("bah, there's ghosts in the machine! got %d, sent %d\n", next_in, play->next_out); + } + if (next_in > play->ack_out) { + /* they've received our packets */ + TRACE("acknowledge out: from %d to %d, sent %d\n", play->ack_out, next_in, play->next_out); + play->ack_out = next_in; + } + else if (next_in < play->ack_out) { + /* they haven't received them yet */ + TRACE("bah, we got an old acknowledge! last %d, got %d\n", play->ack_out, next_in); + } + + if (next_out > play->next_in) { + /* we haven't received all their packets */ + TRACE("bah, we're missing a packet! expected %d, got %d\n", play->next_in, next_out); + return FALSE; + } + else if (next_out < play->next_in) { + /* delayed packet? */ + TRACE("bah, we got an old packet! expected %d, got %d\n", play->next_in, next_out); + return FALSE; + } + + return TRUE; +} + +static int DPNET_ParseAppDesc(DirectPlay8GlobalData *dp8gdData, DPN_APPLICATION_DESC *tdesc, DP8_AppDesc *sdesc, LPVOID src) +{ + LPBYTE pk = src; + memset(tdesc, 0, sizeof(*tdesc)); + tdesc->dwSize = sizeof(*tdesc); + tdesc->dwFlags = sdesc->flags; + memcpy(&tdesc->guidInstance, &sdesc->instGUID, sizeof(GUID)); + memcpy(&tdesc->guidApplication, &sdesc->appGUID, sizeof(GUID)); + tdesc->dwMaxPlayers = sdesc->max_players; + tdesc->dwCurrentPlayers = sdesc->cur_players; + tdesc->pwszSessionName = sdesc->name_ofs ? (LPVOID)(pk + sdesc->name_ofs) : NULL; + tdesc->pwszPassword = sdesc->pass_ofs ? (LPVOID)(pk + sdesc->pass_ofs) : NULL; + tdesc->pvReservedData = sdesc->res_ofs ? (LPVOID)(pk + sdesc->res_ofs) : NULL; + tdesc->dwReservedDataSize = sdesc->res_size; + tdesc->pvApplicationReservedData = sdesc->appres_ofs ? (LPVOID)(pk + sdesc->appres_ofs) : NULL; + tdesc->dwApplicationReservedDataSize = sdesc->appres_size; + return sdesc->name_size + sdesc->pass_size + sdesc->res_size + sdesc->appres_size; +} + +static int DPNET_SizeAppDesc(DirectPlay8GlobalData *dp8gdData, DPN_APPLICATION_DESC *sdesc) +{ + int sz = 0; + if (sdesc->pwszSessionName) + sz += (strlenW(sdesc->pwszSessionName)+1)*sizeof(WCHAR); + if (sdesc->pwszPassword) + sz += (strlenW(sdesc->pwszPassword)+1)*sizeof(WCHAR); + sz += sdesc->dwReservedDataSize; + sz += sdesc->dwApplicationReservedDataSize; + return sz; +} + +static LPBYTE DPNET_FormatAppDesc(DirectPlay8GlobalData *dp8gdData, DP8_AppDesc *tdesc, DPN_APPLICATION_DESC *sdesc, LPVOID dst, LPVOID end) +{ + LPBYTE pk = dst; + LPBYTE ptr = end; + memset(tdesc, 0, sizeof(*tdesc)); + tdesc->size = sizeof(*tdesc); + tdesc->flags = sdesc->dwFlags; + memcpy(&tdesc->instGUID, &sdesc->guidInstance, sizeof(GUID)); + memcpy(&tdesc->appGUID, &sdesc->guidApplication, sizeof(GUID)); + tdesc->max_players = sdesc->dwMaxPlayers; + tdesc->cur_players = sdesc->dwCurrentPlayers; + if (sdesc->pwszSessionName) { + DWORD len = (strlenW(sdesc->pwszSessionName)+1)*sizeof(WCHAR); + memcpy(ptr, sdesc->pwszSessionName, len); + tdesc->name_ofs = ptr - pk; + tdesc->name_size = len; + ptr += len; + } + if (sdesc->pwszPassword) { + DWORD len = (strlenW(sdesc->pwszPassword)+1)*sizeof(WCHAR); + memcpy(ptr, sdesc->pwszPassword, len); + tdesc->pass_ofs = ptr - pk; + tdesc->pass_size = len; + ptr += len; + } + if (sdesc->dwReservedDataSize) { + DWORD len = sdesc->dwReservedDataSize; + memcpy(ptr, sdesc->pvReservedData, len); + tdesc->res_ofs = ptr - pk; + tdesc->res_size = len; + ptr += len; + } + if (sdesc->dwApplicationReservedDataSize) { + DWORD len = sdesc->dwApplicationReservedDataSize; + memcpy(ptr, sdesc->pvApplicationReservedData, len); + tdesc->res_ofs = ptr - pk; + tdesc->res_size = len; + ptr += len; + } + return ptr; +} + +static HRESULT DPNET_SendEnumResponse(DirectPlay8GlobalData *dp8gdData, IDirectPlay8Address *pAddr, WORD id, GUID* guidApp, + PVOID pvResponseData, DWORD dwResponseDataSize, PVOID pvResponseContext) +{ + DPNET_AsyncOp *aop; + DP8_EnumResponse *msg; + LPBYTE ptr; + int sz; + + TRACE("...\n"); + + EnterCriticalSection(&dp8gdData->cs_player); + + sz = DPNET_SizeAppDesc(dp8gdData, &dp8gdData->appdesc); + + aop = DPNET_AsyncAlloc(dp8gdData, 0, sizeof(*msg) + sz); + aop->dwType = 0; + aop->dwFlags = 0; + aop->pvUserContext = pvResponseContext; + IDirectPlay8Address_AddRef(pAddr); + aop->pAddrHost = pAddr; + aop->pAddrDev = NULL; /* FIXME */ + + msg = (LPVOID)aop->PackBuffer.pBufferData; + + msg->tag = DP8SESS_TAG; + msg->command = DP8SESS_ENUM_RESPONSE; + msg->id = id; + + ptr = DPNET_FormatAppDesc(dp8gdData, &msg->app_desc, &dp8gdData->appdesc, &msg->reply_ofs, msg+1); + + if (pvResponseData && dwResponseDataSize) { + msg->reply_ofs = ptr - (LPBYTE)&msg->reply_ofs; + msg->reply_size = dwResponseDataSize; + aop->cUserBuffer++; + aop->UserBuffer[0].pBufferData = pvResponseData; + aop->UserBuffer[0].dwBufferSize = dwResponseDataSize; + } + + aop->dwID = msg->id; + aop->forget = TRUE; + + LeaveCriticalSection(&dp8gdData->cs_player); + + DPNET_StartAsync(dp8gdData, aop); + + /* FIXME: do this in StartAsync when it's done? */ + DPNET_ReturnBufferToApp(dp8gdData, S_OK, pvResponseData, pvResponseContext); + + return S_OK; +} + +static HRESULT DPNET_SendConnectResponse(DirectPlay8GlobalData *dp8gdData, dpPlayer *play) +{ + IDirectPlay8Address *pAddr = play->pAddress; + DPNET_AsyncOp *aop; + DP8_Connect *msg; + + TRACE("...\n"); + + aop = DPNET_AsyncAlloc(dp8gdData, 0, sizeof(*msg)); + aop->dwType = 0; + aop->dwFlags = 0; + IDirectPlay8Address_AddRef(pAddr); + aop->pAddrHost = pAddr; + aop->pAddrDev = NULL; /* FIXME */ + + msg = (LPVOID)aop->PackBuffer.pBufferData; + + msg->command = DP8SESS_CONNECT; + msg->type = DP8SESS_CONN_RESPONSE; + msg->pkt = 0; + msg->ver = DP8SESS_DEFVER; + msg->id = play->conn_id; + msg->time = GetTickCount(); + + aop->dwID = msg->id; + aop->forget = TRUE; + + DPNET_StartAsync(dp8gdData, aop); + + return S_OK; +} + +static HRESULT DPNET_SendConnectAck(DirectPlay8GlobalData *dp8gdData, dpPlayer *play) +{ + IDirectPlay8Address *pAddr = play->pAddress; + DPNET_AsyncOp *aop; + DP8_ConnAck *msg; + + TRACE("...\n"); + + aop = DPNET_AsyncAlloc(dp8gdData, 0, sizeof(*msg)); + aop->dwType = 0; + aop->dwFlags = 0; + IDirectPlay8Address_AddRef(pAddr); + aop->pAddrHost = pAddr; + aop->pAddrDev = NULL; /* FIXME */ + + msg = (LPVOID)aop->PackBuffer.pBufferData; + + msg->command = DP8SESS_ACKNOWLEDGE; + msg->type = DP8SESS_ACK_CONNECT; + msg->unknown_02 = 1; + msg->ver = play->ver; + msg->id = play->conn_id; + msg->time = GetTickCount(); + + aop->dwID = msg->id; + aop->forget = TRUE; + + DPNET_StartAsync(dp8gdData, aop); + + return S_OK; +} + +static HRESULT DPNET_SendPathTest(DirectPlay8GlobalData *dp8gdData, dpPlayer *play) +{ + IDirectPlay8Address *pAddr = play->pAddress; + DPNET_AsyncOp *aop; + DP8_PathTest *msg; + + TRACE("...\n"); + + aop = DPNET_AsyncAlloc(dp8gdData, 0, sizeof(*msg)); + aop->dwType = 0; + aop->dwFlags = 0; + IDirectPlay8Address_AddRef(pAddr); + aop->pAddrHost = pAddr; + aop->pAddrDev = NULL; /* FIXME */ + + msg = (LPVOID)aop->PackBuffer.pBufferData; + + msg->tag = DP8SESS_TAG; + msg->command = DP8SESS_PATH_TEST; + msg->id = 0x2551; + msg->key1 = DPNET_Random(dp8gdData); + msg->key2 = DPNET_Random(dp8gdData) * 49; + + aop->dwID = msg->key1; + aop->forget = TRUE; + + DPNET_StartAsync(dp8gdData, aop); + + return S_OK; +} + +static HRESULT DPNET_SendNoData(DirectPlay8GlobalData *dp8gdData, dpPlayer *play, BYTE type, WORD pkt) +{ + IDirectPlay8Address *pAddr = play->pAddress; + DPNET_AsyncOp *aop; + DP8_Data *msg; + + TRACE("...\n"); + + aop = DPNET_AsyncAlloc(dp8gdData, 0, sizeof(*msg)); + aop->dwType = 0; + aop->dwFlags = 0; + IDirectPlay8Address_AddRef(pAddr); + aop->pAddrHost = pAddr; + aop->pAddrDev = NULL; /* FIXME */ + + msg = (LPVOID)aop->PackBuffer.pBufferData; + + msg->command = DP8SESS_DATA_RELIABLE; + msg->type = type; + msg->next_out = play->next_out++; + msg->next_in = play->next_in; + play->ack_in = play->next_in; + + aop->dwID = msg->next_out; + aop->forget = TRUE; + + DPNET_StartAsync(dp8gdData, aop); + + return S_OK; +} + +static HRESULT DPNET_SendDataAck(DirectPlay8GlobalData *dp8gdData, dpPlayer *play) +{ + IDirectPlay8Address *pAddr = play->pAddress; + DPNET_AsyncOp *aop; + DP8_DataAck *msg; + + TRACE("...\n"); + + aop = DPNET_AsyncAlloc(dp8gdData, 0, sizeof(*msg)); + aop->dwType = 0; + aop->dwFlags = 0; + IDirectPlay8Address_AddRef(pAddr); + aop->pAddrHost = pAddr; + aop->pAddrDev = NULL; /* FIXME */ + + msg = (LPVOID)aop->PackBuffer.pBufferData; + + msg->command = DP8SESS_ACKNOWLEDGE; + msg->type = DP8SESS_ACK_DATA_RELIABLE; + msg->unknown_02 = 1; + msg->next_out = play->next_out; + msg->next_in = play->next_in; + play->ack_in = play->next_in; + msg->time = GetTickCount(); + + aop->dwID = msg->next_out; + aop->forget = TRUE; + + DPNET_StartAsync(dp8gdData, aop); + + return S_OK; +} + +static HRESULT DPNET_SendDataAck2(DirectPlay8GlobalData *dp8gdData, dpPlayer *play) +{ + IDirectPlay8Address *pAddr = play->pAddress; + DPNET_AsyncOp *aop; + DP8_DataAck *msg; + + TRACE("...\n"); + + aop = DPNET_AsyncAlloc(dp8gdData, 0, sizeof(*msg) + sizeof(DWORD)); + aop->dwType = 0; + aop->dwFlags = 0; + IDirectPlay8Address_AddRef(pAddr); + aop->pAddrHost = pAddr; + aop->pAddrDev = NULL; /* FIXME */ + + msg = (LPVOID)aop->PackBuffer.pBufferData; + + msg->command = DP8SESS_ACKNOWLEDGE; + msg->type = DP8SESS_ACK_DATA_RELIABLE; + msg->unknown_02 = 3; + msg->next_out = play->next_out; + msg->next_in = play->next_in; + play->ack_in = play->next_in; + msg->time = GetTickCount(); + *(DWORD*)(msg+1) = 1; + + aop->dwID = msg->next_out; + aop->forget = TRUE; + + DPNET_StartAsync(dp8gdData, aop); + + return S_OK; +} + +static HRESULT DPNET_SendPlayerConnect(DirectPlay8GlobalData *dp8gdData, dpPlayer *play) +{ + IDirectPlay8Address *pAddr = play->pAddress; + DPNET_AsyncOp *aop; + DP8_PlayerConnect *msg; + dpPlayer *lplay = &dp8gdData->localPlayer; + LPBYTE pk, ptr; + DWORD name_len; + + TRACE("...\n"); + + DPNET_LockPlayer(dp8gdData, lplay); + + name_len = lplay->name ? (strlenW(lplay->name)+1)*sizeof(WCHAR) : 0; + + aop = DPNET_AsyncAlloc(dp8gdData, 0, sizeof(*msg) + + lplay->conn_data_len + name_len + lplay->data_len); + aop->dwType = 0; + aop->dwFlags = 0; + IDirectPlay8Address_AddRef(pAddr); + aop->pAddrHost = pAddr; + aop->pAddrDev = NULL; /* FIXME */ + + msg = (LPVOID)aop->PackBuffer.pBufferData; + + msg->msg.command = DP8SESS_MESSAGE; + msg->msg.type = 0; + msg->msg.next_out = play->next_out++; + msg->msg.next_in = play->next_in; + play->ack_in = msg->msg.next_in; + msg->msg.msg = DP8SESS_MSG_PLAYER_CONNECT; + + pk = (LPBYTE)msg + sizeof(msg->msg); + + msg->flags = DP8SESS_CONNF_PEER; + msg->dplay_ver = 7; + memcpy(&msg->instGUID, &dp8gdData->appdesc.guidInstance, sizeof(GUID)); + memcpy(&msg->appGUID, &dp8gdData->appdesc.guidApplication, sizeof(GUID)); + + ptr = (LPBYTE)(msg+1); + + /* FIXME: add address */ + /* FIXME: add password */ + /* FIXME: add url */ + + /* connect data */ + if (lplay->conn_data_len) { + msg->conn_ofs = ptr - pk; + msg->conn_size = lplay->conn_data_len; + memcpy(ptr, lplay->conn_data, lplay->conn_data_len); + ptr += lplay->conn_data_len; + } + + /* name */ + if (lplay->name) { + msg->name_ofs = ptr - pk; + msg->name_size = name_len; + memcpy(ptr, lplay->name, name_len); + ptr += name_len; + } + + /* player data */ + if (lplay->data_len) { + msg->data_ofs = ptr - pk; + msg->data_size = lplay->data_len; + memcpy(ptr, lplay->conn_data, lplay->data_len); + ptr += lplay->data_len; + } + + aop->dwID = msg->msg.next_out; + aop->forget = TRUE; + + DPNET_StartAsync(dp8gdData, aop); + + DPNET_UnlockPlayer(dp8gdData, lplay); + + return S_OK; +} + +static HRESULT DPNET_SendSessionInfo(DirectPlay8GlobalData *dp8gdData, dpPlayer *play) +{ + IDirectPlay8Address *pAddr = play->pAddress; + DPNET_AsyncOp *aop; + DP8_SessionInfo *msg; + DP8_PlayerInfo *pi; + dpPlayer *cplay; + DWORD players; + LPBYTE pk, ptr; + int sz; + + TRACE("...\n"); + + EnterCriticalSection(&dp8gdData->cs_player); + + sz = sizeof(*msg); + sz += DPNET_SizeAppDesc(dp8gdData, &dp8gdData->appdesc); + sz += play->conn_data_len; + + /* count players */ + players = 0; + cplay = &dp8gdData->localPlayer; + players++; + sz += sizeof(DP8_PlayerInfo); + if (cplay->name) + sz += (strlenW(cplay->name)+1)*sizeof(WCHAR); + if (cplay->data) + sz += cplay->data_len; + /* don't attach URL to ourselves */ + cplay = dp8gdData->remotePlayers; + while (cplay) { + if (cplay->status == PLAYER_ACCEPTED || + cplay->status == PLAYER_ACTIVE) { + DWORD url_len = 0; + players++; + sz += sizeof(DP8_PlayerInfo); + IDirectPlay8Address_GetURLA(cplay->pAddress, NULL, &url_len); + sz += url_len; + if (cplay->name) + sz += (strlenW(cplay->name)+1)*sizeof(WCHAR); + if (cplay->data) + sz += cplay->data_len; + } + cplay = cplay->next; + } + + aop = DPNET_AsyncAlloc(dp8gdData, 0, sz); + aop->dwType = 0; + aop->dwFlags = 0; + IDirectPlay8Address_AddRef(pAddr); + aop->pAddrHost = pAddr; + aop->pAddrDev = NULL; /* FIXME */ + + msg = (LPVOID)aop->PackBuffer.pBufferData; + + msg->msg.command = DP8SESS_MESSAGE; + msg->msg.type = 0; + msg->msg.next_out = play->next_out++; + msg->msg.next_in = play->next_in; + play->ack_in = msg->msg.next_in; + msg->msg.msg = DP8SESS_MSG_SESSION_INFO; + + pk = (LPBYTE)msg + sizeof(msg->msg); + + msg->player_id = play->dwPlayerID; + msg->ver = 3; + + msg->entries = players; + + pi = (LPVOID)(msg+1); + + ptr = (LPVOID)(pi+players); + + /* players */ + cplay = &dp8gdData->localPlayer; + pi->group_id = cplay->dwPlayerID; + pi->flags = DP8SESS_PINFOF_PEER; + if (dp8gdData->is_host) + pi->flags |= DP8SESS_PINFOF_HOST; + pi->ver = 2; + pi->dplay_ver = cplay->dplay_ver; + if (cplay->name) { + DWORD len = (strlenW(cplay->name)+1)*sizeof(WCHAR); + pi->name_ofs = ptr - pk; + pi->name_size = len; + memcpy(ptr, cplay->name, len); + ptr += len; + } + if (cplay->data) { + pi->data_ofs = ptr - pk; + pi->data_size = cplay->data_len; + memcpy(ptr, cplay->data, cplay->data_len); + ptr += cplay->data_len; + } + pi++; + + cplay = dp8gdData->remotePlayers; + while (cplay) { + if (cplay->status == PLAYER_ACCEPTED || + cplay->status == PLAYER_ACTIVE) { + DWORD url_len = sz - (ptr - (LPBYTE)msg); + + pi->group_id = cplay->dwPlayerID; + pi->flags = DP8SESS_PINFOF_PEER; + if (cplay == dp8gdData->remoteHost) + pi->flags |= DP8SESS_PINFOF_HOST; + pi->ver = 2; + pi->dplay_ver = cplay->dplay_ver; + + IDirectPlay8Address_GetURLA(cplay->pAddress, (LPVOID)ptr, &url_len); + pi->url_ofs = ptr - pk; + pi->url_size = url_len; + ptr += url_len; + + if (cplay->name) { + DWORD len = (strlenW(cplay->name)+1)*sizeof(WCHAR); + pi->name_ofs = ptr - pk; + pi->name_size = len; + memcpy(ptr, cplay->name, len); + ptr += len; + } + if (cplay->data) { + pi->data_ofs = ptr - pk; + pi->data_size = cplay->data_len; + memcpy(ptr, cplay->data, cplay->data_len); + ptr += cplay->data_len; + } + pi++; + } + cplay = cplay->next; + } + + ptr = DPNET_FormatAppDesc(dp8gdData, &msg->app_desc, &dp8gdData->appdesc, pk, ptr); + + /* attach reply data from INDICATE_CONNECT */ + if (play->conn_data_len) { + msg->reply_ofs = ptr - pk; + msg->reply_size = play->conn_data_len; + memcpy(ptr, play->conn_data, play->conn_data_len); + ptr += play->conn_data_len; + } + + aop->dwID = msg->msg.next_out; + aop->forget = TRUE; + + DPNET_StartAsync(dp8gdData, aop); + + LeaveCriticalSection(&dp8gdData->cs_player); + + /* release reply data */ + DPNET_ReturnBufferToApp(dp8gdData, S_OK, play->conn_data, play->conn_data_ctx); + play->conn_data = NULL; + play->conn_data_len = 0; + play->conn_data_ctx = 0; + + return S_OK; +} + +static HRESULT DPNET_SendSessionAck(DirectPlay8GlobalData *dp8gdData, dpPlayer *play) +{ + IDirectPlay8Address *pAddr = play->pAddress; + DPNET_AsyncOp *aop; + DP8_SessionAck *msg; + + TRACE("...\n"); + + aop = DPNET_AsyncAlloc(dp8gdData, 0, sizeof(*msg)); + aop->dwType = 0; + aop->dwFlags = 0; + IDirectPlay8Address_AddRef(pAddr); + aop->pAddrHost = pAddr; + aop->pAddrDev = NULL; /* FIXME */ + + msg = (LPVOID)aop->PackBuffer.pBufferData; + + msg->msg.command = DP8SESS_MESSAGE; + msg->msg.type = 0; + msg->msg.next_out = play->next_out++; + msg->msg.next_in = play->next_in; + play->ack_in = play->next_in; + msg->msg.msg = DP8SESS_MSG_SESSION_ACK; + + aop->dwID = msg->msg.next_out; + aop->forget = TRUE; + + DPNET_StartAsync(dp8gdData, aop); + + return S_OK; +} + +static HRESULT DPNET_SendAppDescUpdate(DirectPlay8GlobalData *dp8gdData, dpPlayer *play) +{ + IDirectPlay8Address *pAddr = play->pAddress; + DPNET_AsyncOp *aop; + DP8_AppDescUpdate *msg; + int sz; + + TRACE("...\n"); + + EnterCriticalSection(&dp8gdData->cs_player); + + sz = DPNET_SizeAppDesc(dp8gdData, &dp8gdData->appdesc); + + aop = DPNET_AsyncAlloc(dp8gdData, 0, sizeof(*msg) + sz); + aop->dwType = 0; + aop->dwFlags = 0; + IDirectPlay8Address_AddRef(pAddr); + aop->pAddrHost = pAddr; + aop->pAddrDev = NULL; /* FIXME */ + + msg = (LPVOID)aop->PackBuffer.pBufferData; + + msg->msg.command = DP8SESS_MESSAGE; + msg->msg.type = 0; + msg->msg.next_out = play->next_out++; + msg->msg.next_in = play->next_in; + play->ack_in = play->next_in; + msg->msg.msg = DP8SESS_MSG_APPDESC_UPDATE; + + DPNET_FormatAppDesc(dp8gdData, &msg->app_desc, &dp8gdData->appdesc, &msg->app_desc, msg+1); + + aop->dwID = msg->msg.next_out; + aop->forget = TRUE; + + LeaveCriticalSection(&dp8gdData->cs_player); + + DPNET_StartAsync(dp8gdData, aop); + + return S_OK; +} + +static HRESULT DPNET_SendPeerConnect(DirectPlay8GlobalData *dp8gdData, dpPlayer *play) +{ + IDirectPlay8Address *pAddr = play->pAddress; + DPNET_AsyncOp *aop; + DP8_PeerConnect *msg; + + TRACE("...\n"); + + aop = DPNET_AsyncAlloc(dp8gdData, 0, sizeof(*msg)); + aop->dwType = 0; + aop->dwFlags = 0; + IDirectPlay8Address_AddRef(pAddr); + aop->pAddrHost = pAddr; + aop->pAddrDev = NULL; /* FIXME */ + + msg = (LPVOID)aop->PackBuffer.pBufferData; + + msg->msg.command = DP8SESS_MESSAGE; + msg->msg.type = 0; + msg->msg.next_out = play->next_out++; + msg->msg.next_in = play->next_in; + play->ack_in = play->next_in; + msg->msg.msg = DP8SESS_MSG_PEER_CONNECT; + msg->player_id = play->dwPlayerID; + msg->ver = 4; + + aop->dwID = msg->msg.next_out; + aop->forget = TRUE; + + DPNET_StartAsync(dp8gdData, aop); + + return S_OK; +} + +static HRESULT DPNET_SendTableVer(DirectPlay8GlobalData *dp8gdData, dpPlayer *play) +{ + IDirectPlay8Address *pAddr = play->pAddress; + DPNET_AsyncOp *aop; + DP8_TableVer *msg; + + TRACE("...\n"); + + aop = DPNET_AsyncAlloc(dp8gdData, 0, sizeof(*msg)); + aop->dwType = 0; + aop->dwFlags = 0; + IDirectPlay8Address_AddRef(pAddr); + aop->pAddrHost = pAddr; + aop->pAddrDev = NULL; /* FIXME */ + + msg = (LPVOID)aop->PackBuffer.pBufferData; + + msg->msg.command = DP8SESS_MESSAGE; + msg->msg.type = 0; + msg->msg.next_out = play->next_out++; + msg->msg.next_in = play->next_in; + play->ack_in = play->next_in; + msg->msg.msg = DP8SESS_MSG_TABLE_VER; + msg->ver = 4; + + aop->dwID = msg->msg.next_out; + aop->forget = TRUE; + + DPNET_StartAsync(dp8gdData, aop); + + return S_OK; +} + +static BOOL DPNET_ParseSessionInfo(DirectPlay8GlobalData *dp8gdData, void *pk, int pklen, dpPlayer *play) +{ + DP8_SessionInfo *msg = pk; + DP8_PlayerInfo *pi; + DPN_APPLICATION_DESC desc; + dpPlayer *cplay = &dp8gdData->localPlayer; + IDirectPlay8Address *pAddr = NULL; + HRESULT hr; + LPBYTE p; + DWORD c; + + if (cplay->status != PLAYER_CONNECTED) { + TRACE("skipping!\n"); + return FALSE; + } + + play->status = PLAYER_ACCEPTED; + cplay->status = PLAYER_ACCEPTED; + + hr = DPNET_CreateDirectPlay8Address(NULL, &IID_IDirectPlay8Address, (LPVOID *)&pAddr); + + DPNET_ParseAppDesc(dp8gdData, &desc, &msg->app_desc, &msg->reply_ofs); + + EnterCriticalSection(&dp8gdData->cs_player); + + memcpy(&dp8gdData->appdesc.guidInstance, &desc.guidInstance, sizeof(GUID)); + memcpy(&dp8gdData->appdesc.guidApplication, &desc.guidApplication, sizeof(GUID)); + DPNET_SetAppDesc(dp8gdData, &desc); + + p = (LPBYTE)msg + sizeof(msg->msg); + + /* players */ + pi = (LPVOID)(msg+1); + for (c=0; centries; c++) { + BOOL was_new = FALSE; + dpPlayer *nplay; + nplay = DPNET_FindPlayerByID(dp8gdData, pi->group_id); + if (!nplay) { + /* not previously identified player */ + was_new = TRUE; + if (pi->group_id == msg->player_id) { + /* it's us */ + nplay = &dp8gdData->localPlayer; + nplay->dwPlayerID = msg->player_id; + } else + if (pi->url_size) { + /* it's a new player */ + BOOL found; + IDirectPlay8Address_BuildFromURLA(pAddr, (LPVOID)(p + pi->url_ofs)); + nplay = DPNET_MakePlayer(dp8gdData, pAddr, &found); + nplay->status = PLAYER_ACCEPTED; + } else { + /* it's our host */ + nplay = dp8gdData->remoteHost; + nplay->dwPlayerID = pi->group_id; + } + } + + nplay->dplay_ver = pi->dplay_ver; + if (nplay->name) { + HeapFree(GetProcessHeap(), 0, nplay->name); + nplay->name = NULL; + } + if (nplay->data) { + HeapFree(GetProcessHeap(), 0, nplay->data); + nplay->data = NULL; + nplay->data_len = 0; + } + if (pi->name_size) { + nplay->name = HeapAlloc(GetProcessHeap(), 0, pi->name_size); + memcpy(nplay->name, p + pi->name_ofs, pi->name_size); + } + if (pi->data_size) { + nplay->data = HeapAlloc(GetProcessHeap(), 0, pi->data_size); + memcpy(nplay->data, p + pi->data_ofs, pi->data_size); + } + + if (was_new) { + DPNMSG_CREATE_PLAYER resp; + memset(&resp, 0, sizeof(resp)); + resp.dwSize = sizeof(resp); + resp.dpnidPlayer = nplay->dwPlayerID; + resp.pvPlayerContext = nplay->pvPlayerContext; + TRACE("dispatching Player Creation\n"); + hr = dp8gdData->pfMessageHandler(dp8gdData->pvUserContext, DPN_MSGID_CREATE_PLAYER, &resp); + TRACE("returned 0x%08x\n", hr); + nplay->pvPlayerContext = resp.pvPlayerContext; + if (nplay != &dp8gdData->localPlayer) { + nplay->status = PLAYER_ACTIVE; + dp8gdData->appdesc.dwCurrentPlayers++; + } + } + + pi++; + } + + /* grab connection reply data */ + if (play->reply_data) { + HeapFree(GetProcessHeap(), 0, play->reply_data); + play->reply_data = NULL; + play->reply_data_len = 0; + } + if (msg->reply_size) { + play->reply_data = HeapAlloc(GetProcessHeap(), 0, msg->reply_size); + memcpy(play->reply_data, p + msg->reply_ofs, msg->reply_size); + } + + LeaveCriticalSection(&dp8gdData->cs_player); + + IDirectPlay8Address_Release(pAddr); + + return TRUE; +} + +static void DPNET_RecvMessage(DirectPlay8GlobalData *dp8gdData, void *pk, int pklen, dpPlayer *play) +{ + DP8_Message *pm = pk; + LPBYTE hdr = (LPVOID)(pm+1); + DPNET_AsyncOp *aop = NULL; + HRESULT hr; + + switch (pm->msg) { + case DP8SESS_MSG_PLAYER_CONNECT: + if (dp8gdData->is_host) { + DP8_PlayerConnect *msg = pk; + + DPNET_LockPlayer(dp8gdData, play); + if (play->status == PLAYER_CONNECTED) { + DPNMSG_INDICATE_CONNECT resp; + + play->dplay_ver = msg->dplay_ver; + /* FIXME: verify flags? */ + /* FIXME: verify password? */ + /* FIXME: verify GUIDs? */ + /* FIXME: grab address? */ + + if (msg->name_size) { + play->name = HeapAlloc(GetProcessHeap(), 0, msg->name_size); + memcpy(play->name, (LPVOID)(hdr + msg->name_ofs), msg->name_size); + TRACE("player name: %s\n", debugstr_w(play->name)); + } + + if (msg->data_size) { + play->data = HeapAlloc(GetProcessHeap(), 0, msg->data_size); + memcpy(play->name, (LPVOID)(hdr + msg->data_ofs), msg->data_size); + play->data_len = msg->data_size; + } + + memset(&resp, 0, sizeof(resp)); + resp.dwSize = sizeof(resp); + resp.pAddressPlayer = play->pAddress; + resp.pAddressDevice = NULL; /* FIXME */ + TRACE("connect data size: %d\n", msg->conn_size); + if (msg->conn_size) { + resp.pvUserConnectData = (LPVOID)(hdr + msg->conn_ofs); + resp.dwUserConnectDataSize = msg->conn_size; + } + TRACE("dispatching Connect indication\n"); + hr = dp8gdData->pfMessageHandler(dp8gdData->pvUserContext, DPN_MSGID_INDICATE_CONNECT, &resp); + TRACE("returned 0x%08x\n", hr); + if (hr != DPN_OK) { + /* connection rejected */ + play->status = PLAYER_REJECTED; + DPNET_UnlockPlayer(dp8gdData, play); + /* FIXME: send reject response */ + break; + } + /* player accepted, allocate ID and stuff */ + play->dwPlayerID = InterlockedExchangeAdd(&dp8gdData->player_id, 1); + play->pvPlayerContext = resp.pvPlayerContext; + play->status = PLAYER_ACCEPTED; + play->conn_data = resp.pvReplyData; + play->conn_data_len = resp.dwReplyDataSize; + play->conn_data_ctx = resp.pvReplyContext; + DPNET_SendSessionInfo(dp8gdData, play); + } + DPNET_UnlockPlayer(dp8gdData, play); + break; + } + TRACE("ignoring player message since we're not hosting\n"); + break; + case DP8SESS_MSG_SESSION_INFO: + if (!dp8gdData->is_host && play == dp8gdData->remoteHost) { + if (!DPNET_ParseSessionInfo(dp8gdData, pk, pklen, play)) + break; + + DPNET_SendSessionAck(dp8gdData, play); + DPNET_SendPathTest(dp8gdData, play); + break; + } + TRACE("ignoring session info message since it's not from host\n"); + break; + case DP8SESS_MSG_SESSION_ACK: + if (dp8gdData->is_host) { + /* FIXME: Windows's appdesc packet contains the updated number of players + * (including the connecting one) */ + + /* DPNET_SendAppDescUpdate(dp8gdData, play); */ + DPNET_SendPeerConnect(dp8gdData, play); + } + break; + case DP8SESS_MSG_PEER_CONNECT: + if (!dp8gdData->is_host) { + /* FIXME: what else to do here? */ + + DPNET_SendTableVer(dp8gdData, play); + + /* FIXME: when exactly are we fully connected? + * Well, this seems close enough for now, I think. */ + if (dp8gdData->localPlayer.status == PLAYER_ACCEPTED) { + DPNMSG_CONNECT_COMPLETE resp; + + aop = DPNET_AsyncSearch(dp8gdData, DPN_MSGID_CONNECT_COMPLETE, 0); + + memset(&resp, 0, sizeof(resp)); + resp.dwSize = sizeof(resp); + if (aop) { + resp.hAsyncOp = (DPNHANDLE)aop; + resp.pvUserContext = aop->pvUserContext; + } + resp.hResultCode = S_OK; + resp.dpnidLocal = dp8gdData->localPlayer.dwPlayerID; + resp.pvApplicationReplyData = play->reply_data; + resp.dwApplicationReplyDataSize = play->reply_data_len; + TRACE("dispatching Connect completion\n"); + hr = dp8gdData->pfMessageHandler(dp8gdData->pvUserContext, DPN_MSGID_CONNECT_COMPLETE, &resp); + TRACE("returned 0x%08x\n", hr); + dp8gdData->localPlayer.status = PLAYER_ACTIVE; + dp8gdData->appdesc.dwCurrentPlayers++; + + if (aop) { + DPNET_AsyncRemove(dp8gdData, aop); + DPNET_AsyncSignal(dp8gdData, aop); + } + } + } + break; + case DP8SESS_MSG_TABLE_VER: + if (dp8gdData->is_host) { + /* FIXME: when exactly is the player fully connected? + * Well, this seems close enough for now, I think; + * it's supposed to connected to the other peers and stuff, + * but that's not implemented yet */ + DPNET_LockPlayer(dp8gdData, play); + if (play->status == PLAYER_ACCEPTED) { + DPNMSG_CREATE_PLAYER resp; + memset(&resp, 0, sizeof(resp)); + resp.dwSize = sizeof(resp); + resp.dpnidPlayer = play->dwPlayerID; + resp.pvPlayerContext = play->pvPlayerContext; + TRACE("dispatching Player Creation\n"); + hr = dp8gdData->pfMessageHandler(dp8gdData->pvUserContext, DPN_MSGID_CREATE_PLAYER, &resp); + TRACE("returned 0x%08x\n", hr); + play->pvPlayerContext = resp.pvPlayerContext; + play->status = PLAYER_ACTIVE; + /* DPNET_SendNoData(dp8gdData, play, 0x0, 0x0); */ + } + DPNET_SendDataAck(dp8gdData, play); + DPNET_UnlockPlayer(dp8gdData, play); + } + break; + default: + TRACE("unknown packet, but acknowledging anyway\n"); + DPNET_SendDataAck(dp8gdData, play); + } +} + +static BOOL DPNET_RecvData(DirectPlay8GlobalData *dp8gdData, void *pk, int pklen, dpPlayer *play, DWORD flags, DPNHANDLE buf) +{ + DPNMSG_RECEIVE resp; + HRESULT hr; + + if (!pklen) return FALSE; + + memset(&resp, 0, sizeof(resp)); + resp.dwSize = sizeof(resp); + resp.dpnidSender = play->dwPlayerID; + resp.pvPlayerContext = play->pvPlayerContext; + resp.pReceiveData = pk; + resp.dwReceiveDataSize = pklen; + resp.hBufferHandle = buf; + resp.dwReceiveFlags = flags; + TRACE("dispatching Receive (ptr %p, len %d)\n", pk, pklen); + hr = dp8gdData->pfMessageHandler(dp8gdData->pvUserContext, DPN_MSGID_RECEIVE, &resp); + TRACE("returned 0x%08x\n", hr); + return (hr == DPNSUCCESS_PENDING); +} + +static BOOL DPNET_RecvPacket(DirectPlay8GlobalData *dp8gdData, void *pk, int pklen, IDirectPlay8Address *pAddr) +{ + LPBYTE hdr = pk; + DPNET_AsyncOp *aop = NULL; + HRESULT hr; + BOOL keep = FALSE; + + debug_hexdump(pk, pklen); + + if (pklen >= 2 && hdr[0] == DP8SESS_TAG) { + switch (hdr[1]) { + case DP8SESS_ENUM_REQUEST: + if (dp8gdData->is_host) { + DP8_EnumRequest *msg = pk; + GUID *guidApp = NULL; + int sz = sizeof(*msg); + if (msg->type == DP8SESS_ENUM_REQ_WITH_GUID) { guidApp = (LPVOID)(msg+1); sz += sizeof(GUID); } + if ((!guidApp) || IsEqualGUID(guidApp, &dp8gdData->appdesc.guidApplication)) { + DPNMSG_ENUM_HOSTS_QUERY resp; + memset(&resp, 0, sizeof(resp)); + resp.dwSize = sizeof(resp); + resp.pAddressSender = pAddr; + resp.pAddressDevice = NULL; /* FIXME */ + if (pklen > sz) { + resp.pvReceivedData = (LPVOID)(hdr + sz); + resp.dwReceivedDataSize = pklen - sz; + } + resp.dwMaxResponseDataSize = 0; /* FIXME */ + TRACE("dispatching EnumHosts query\n"); + hr = dp8gdData->pfMessageHandler(dp8gdData->pvUserContext, DPN_MSGID_ENUM_HOSTS_QUERY, &resp); + TRACE("returned 0x%08x\n", hr); + if (hr != DPN_OK) break; + hr = DPNET_SendEnumResponse(dp8gdData, pAddr, msg->id, guidApp, + resp.pvResponseData, resp.dwResponseDataSize, + resp.pvResponseContext); + break; + } + } + /* we should probably send some reject packet? */ + TRACE("ignoring enum request since we're not hosting\n"); + break; + case DP8SESS_ENUM_RESPONSE: + { + DP8_EnumResponse *msg = pk; + DPNMSG_ENUM_HOSTS_RESPONSE resp; + DPN_APPLICATION_DESC desc; + + aop = DPNET_AsyncSearch(dp8gdData, DPN_MSGID_ENUM_HOSTS_RESPONSE, msg->id); + if (!aop) break; + memset(&resp, 0, sizeof(resp)); + resp.dwSize = sizeof(resp); + resp.pAddressSender = pAddr; + resp.pAddressDevice = aop->pAddrDev; + resp.pApplicationDescription = &desc; + resp.pvUserContext = aop->pvUserContext; + DPNET_ParseAppDesc(dp8gdData, &desc, &msg->app_desc, &msg->reply_ofs) + sizeof(*msg); + TRACE("session name: %s\n", debugstr_w(desc.pwszSessionName)); + TRACE("max players: %d, cur players: %d\n", desc.dwMaxPlayers, desc.dwCurrentPlayers); + if (msg->reply_size) { + resp.pvResponseData = ((LPBYTE)&msg->reply_ofs) + msg->reply_ofs; + resp.dwResponseDataSize = msg->reply_size; + } + TRACE("dispatching EnumHosts response\n"); + hr = dp8gdData->pfMessageHandler(dp8gdData->pvUserContext, DPN_MSGID_ENUM_HOSTS_RESPONSE, &resp); + TRACE("returned 0x%08x\n", hr); + } + /* for now, we're going to assume that's it. */ + DPNET_AsyncRemove(dp8gdData, aop); + DPNET_AsyncSignal(dp8gdData, aop); + break; + default: + TRACE("unknown session packet 0 %d\n", hdr[1]); + } + } + else if (pklen >= 2) { + switch (hdr[0]) { + case DP8SESS_CONNECT: + { + DP8_Connect *msg = pk; + switch (msg->type) { + case DP8SESS_CONN_REQUEST: + if (dp8gdData->is_host) { + BOOL found; + dpPlayer *play = DPNET_MakePlayer(dp8gdData, pAddr, &found); + + DPNET_LockPlayer(dp8gdData, play); + if (!found) { + play->conn_id = msg->id; + play->ver = DP8SESS_MINVER(msg->ver, DP8SESS_DEFVER); + play->status = PLAYER_RESPONSE_SENT; + DPNET_SendConnectResponse(dp8gdData, play); + } + else if (play->status == PLAYER_RESPONSE_SENT) { + /* in case the first response was lost */ + DPNET_SendConnectResponse(dp8gdData, play); + } + DPNET_UnlockPlayer(dp8gdData, play); + break; + } + /* we should probably send some reject packet? */ + TRACE("ignoring connect request since we're not hosting\n"); + break; + case DP8SESS_CONN_RESPONSE: + { + dpPlayer *play = DPNET_FindPlayerByAddr(dp8gdData, pAddr); + + if (!play) { + TRACE("couldn't find connecting player\n"); + break; + } + + DPNET_LockPlayer(dp8gdData, play); + if (play->status == PLAYER_REQUEST_SENT) { + play->ver = DP8SESS_MINVER(msg->ver, DP8SESS_DEFVER); + play->status = PLAYER_CONNECTED; + TRACE("connected (ver %08x)\n", play->ver); + + DPNET_SendConnectAck(dp8gdData, play); + + if (play == dp8gdData->remoteHost) { + dp8gdData->localPlayer.status = PLAYER_CONNECTED; + DPNET_SendPlayerConnect(dp8gdData, play); + } + + /* DPNET_SendNoData(dp8gdData, play, 0x0, 0x0); */ + } + DPNET_UnlockPlayer(dp8gdData, play); + } + break; + default: + TRACE("unknown connect packet %d\n", msg->type); + } + } + break; + case DP8SESS_ACKNOWLEDGE: + { + DP8_ConnAck *msg = pk; + dpPlayer *play = DPNET_FindPlayerByAddr(dp8gdData, pAddr); + + if (!play) { + TRACE("couldn't find acknowledging player\n"); + break; + } + + switch (msg->type) { + case DP8SESS_ACK_CONNECT: + { + DPNET_LockPlayer(dp8gdData, play); + if (play->status == PLAYER_RESPONSE_SENT) { + TRACE("connected (ver %08x)\n", play->ver); + play->ver = msg->ver; + play->status = PLAYER_CONNECTED; + /* DPNET_SendNoData(dp8gdData, play, 0x0, 0x0); */ + } + DPNET_UnlockPlayer(dp8gdData, play); + } + break; + case DP8SESS_ACK_DATA_RELIABLE: + /* FIXME */ + break; + default: + TRACE("unknown acknowledge packet %d\n", msg->type); + } + } + break; + case DP8SESS_MESSAGE: + { + DP8_Message *msg = pk; + dpPlayer *play = DPNET_FindPlayerByAddr(dp8gdData, pAddr); + + if (!play) { + TRACE("couldn't find messaging player\n"); + break; + } + + DPNET_LockPlayer(dp8gdData, play); + + if (!DPNET_GotAck(dp8gdData, play, msg->next_out, msg->next_in)) { + TRACE("ignoring packet due to bad sequence\n"); + DPNET_UnlockPlayer(dp8gdData, play); + break; + } + + play->next_in++; + + DPNET_UnlockPlayer(dp8gdData, play); + + DPNET_RecvMessage(dp8gdData, pk, pklen, play); + } + break; + case DP8SESS_DATA_RELIABLE: + { + DP8_Data *msg = pk; + dpPlayer *play = DPNET_FindPlayerByAddr(dp8gdData, pAddr); + DWORD flags = 0; + + if (!play) { + TRACE("couldn't find messaging player\n"); + break; + } + + /* first empty data packet: */ + /* 3f 00 00 00 */ + /* acknowledge with: */ + /* 80 06 01 00 01 01 00 00 */ + + /* new empty data packet: */ + /* 3f 0a 02 02 */ + /* acknowledge with: */ + /* 80 06 03 00 02 01 00 00 01 00 00 00 */ + + DPNET_LockPlayer(dp8gdData, play); + + if (!DPNET_GotAck(dp8gdData, play, msg->next_out, msg->next_in)) { + TRACE("ignoring packet due to bad sequence\n"); + DPNET_UnlockPlayer(dp8gdData, play); + break; + } + + play->next_in++; + + switch (msg->type) { + case 0x00: + DPNET_SendDataAck(dp8gdData, play); + flags |= DPNRECEIVE_GUARANTEED; + keep = DPNET_RecvData(dp8gdData, msg+1, pklen - sizeof(*msg), play, flags, (DPNHANDLE)pk); + break; + case 0x0a: + DPNET_SendDataAck2(dp8gdData, play); + keep = DPNET_RecvData(dp8gdData, msg+1, pklen - sizeof(*msg), play, flags, (DPNHANDLE)pk); + break; + } + + DPNET_UnlockPlayer(dp8gdData, play); + } + break; + default: + TRACE("unknown session packet %d\n", hdr[0]); + } + } + return keep; +} + +static HRESULT DPNET_SendPacket(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop) +{ + HRESULT hr; + + DPNET_AsyncInsert(dp8gdData, aop); + /* FIXME: enter into appropriate-priority queue first, + * network buffers may be full and other packets may have priority. */ + hr = IDirectPlay8ServiceProvider_SendTo(dp8gdData->sp, aop->pAddrHost, + &aop->PackBuffer, aop->cUserBuffer+1, 0); + if (hr == DPNERR_NOTREADY) { + /* once we've implemented queues, we should make the + * SP call us as soon as it's ready... (WSAEventSelect) */ + TRACE("transmit buffers full, must try again later!\n"); + } + + /* FIXME: only dispatch this when sent to all destinations, I think */ + if ((aop->dwType == DPN_MSGID_SEND_COMPLETE) && + !(aop->dwFlags & (DPNSEND_COMPLETEONPROCESS|DPNSEND_NOCOMPLETE))) { + DPNMSG_SEND_COMPLETE resp; + + memset(&resp, 0, sizeof(resp)); + resp.dwSize = sizeof(resp); + resp.hAsyncOp = (DPNHANDLE)aop; + resp.pvUserContext = aop->pvUserContext; + resp.hResultCode = hr; + resp.dwSendTime = GetTickCount() - aop->dwTimeSent; + resp.dwFirstFrameRTT = (DWORD)-1; + resp.dwFirstFrameRetryCount = (DWORD)-1; + resp.dwSendCompleteFlags = 0; + if (aop->dwFlags & DPNSEND_GUARANTEED) + resp.dwSendCompleteFlags |= DPNSENDCOMPLETE_GUARANTEED; + if (aop->cUserBuffer) { + resp.pBuffers = aop->UserBuffer; + resp.dwNumBuffers = aop->cUserBuffer; + } + TRACE("dispatching Send completion\n"); + hr = dp8gdData->pfMessageHandler(dp8gdData->pvUserContext, DPN_MSGID_SEND_COMPLETE, &resp); + TRACE("returned\n"); + } + + /* FIXME: should only remove if the transmit was successful */ + if (aop->forget) { + DPNET_AsyncRemove(dp8gdData, aop); + DPNET_AsyncFree(dp8gdData, aop); + } + return S_OK; +} + +static HRESULT DPNET_StartAsync(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop) +{ +#ifdef FAKE_IT + HRESULT hr; + switch (aop->dwType) { + case DPN_MSGID_ENUM_HOSTS_RESPONSE: + { + static WCHAR sess_name[] = {'F','a','k','e',' ','S','e','s','s','i','o','n',0}; + static WCHAR host_name[] = {'1','2','7','.','0','.','0','.','1',0}; + DPNMSG_ENUM_HOSTS_RESPONSE resp; + DPN_APPLICATION_DESC desc; + IDirectPlay8AddressImpl *addrImpl = (IDirectPlay8AddressImpl *)aop->pAddrDev; + IDirectPlay8Address *addr = NULL; + + DPNET_CreateDirectPlay8Address(NULL, &IID_IDirectPlay8Address, (LPVOID*)&addr); + IDirectPlay8Address_SetSP(addr, &addrImpl->guidSP); + IDirectPlay8Address_AddComponent(addr, DPNA_KEY_HOSTNAME, host_name, sizeof(host_name)/sizeof(WCHAR), DPNA_DATATYPE_STRING); + + memset(&resp, 0, sizeof(resp)); + memset(&desc, 0, sizeof(desc)); + msg = (LPVOID)aop->PackBuffer.pBufferData; + resp.dwSize = sizeof(resp); + resp.pAddressSender = addr; + resp.pAddressDevice = aop->pAddrDev; + resp.pApplicationDescription = &desc; + resp.pvUserContext = aop->pvUserContext; + desc.dwSize = sizeof(desc); + memcpy(&desc.guidApplication, &dp8gdData->guidApplication, sizeof(GUID)); + desc.pwszSessionName = sess_name; + TRACE("dispatching fake EnumHosts response\n"); + hr = dp8gdData->pfMessageHandler(dp8gdData->pvUserContext, aop->dwType, &resp); + TRACE("returned\n"); + IDirectPlay8Address_Release(addr); + } + break; + case DPN_MSGID_CONNECT_COMPLETE: + dp8gdData->localPlayer.dwPlayerID = 1; + { + DPNMSG_CONNECT_COMPLETE resp; + + memset(&resp, 0, sizeof(resp)); + resp.dwSize = sizeof(resp); + resp.hAsyncOp = (DPNHANDLE)aop; + resp.pvUserContext = aop->pvUserContext; + resp.hResultCode = S_OK; + resp.dpnidLocal = dp8gdData->localPlayer.dwPlayerID; + TRACE("dispatching fake Connect response\n"); + hr = dp8gdData->pfMessageHandler(dp8gdData->pvUserContext, aop->dwType, &resp); + TRACE("returned\n"); + } + { + DPNMSG_CREATE_PLAYER resp; + + memset(&resp, 0, sizeof(resp)); + resp.dwSize = sizeof(resp); + resp.dpnidPlayer = 2; + resp.pvPlayerContext = NULL; + TRACE("dispatching fake remote CreatePlayer message\n"); + hr = dp8gdData->pfMessageHandler(dp8gdData->pvUserContext, DPN_MSGID_CREATE_PLAYER, &resp); + dp8gdData->localPlayer.pvPlayerContext = resp.pvPlayerContext; + TRACE("returned\n"); + } + { + DPNMSG_CREATE_PLAYER resp; + + memset(&resp, 0, sizeof(resp)); + resp.dwSize = sizeof(resp); + resp.dpnidPlayer = dp8gdData->localPlayer.dwPlayerID; + resp.pvPlayerContext = dp8gdData->localPlayer.pvPlayerContext; + TRACE("dispatching fake local CreatePlayer message\n"); + hr = dp8gdData->pfMessageHandler(dp8gdData->pvUserContext, DPN_MSGID_CREATE_PLAYER, &resp); + dp8gdData->localPlayer.pvPlayerContext = resp.pvPlayerContext; + TRACE("returned\n"); + } + break; + } + DPNET_AsyncSignal(dp8gdData, aop); +#else + HRESULT hr; + + hr = DPNET_SendPacket(dp8gdData, aop); + TRACE("transmit result: 0x%08x\n", hr); +#endif + + return S_OK; +} + +HRESULT DPNET_GetCaps(DirectPlay8GlobalData *dp8gdData, + DPN_CAPS *const pdpCaps, + const DWORD dwFlags) +{ + DWORD size = min(pdpCaps->dwSize, sizeof(dp8gdData->dpnCaps)); + memcpy(pdpCaps, &dp8gdData->dpnCaps, size); + return S_OK; +} + +HRESULT DPNET_GetSPCaps(DirectPlay8GlobalData *dp8gdData, + const GUID *const pguidSP, + DPN_SP_CAPS *const pdpnSPCaps, + const DWORD dwFlags) +{ + HRESULT hr; + hr = DPNET_InitSP(dp8gdData, pguidSP); + if (FAILED(hr)) return hr; + hr = IDirectPlay8ServiceProvider_GetSPCaps(dp8gdData->sp, pdpnSPCaps, dwFlags); + return hr; +} + +HRESULT DPNET_CancelAsyncOperation(DirectPlay8GlobalData *dp8gdData, + const DPNHANDLE hAsyncHandle, + const DWORD dwFlags) +{ + DPNET_AsyncOp *aop; + + if (!dwFlags) { + aop = (DPNET_AsyncOp *)hAsyncHandle; +#if 0 + DPNET_AsyncRemove(dp8gdData, aop); + DPNET_AsyncSignal(dp8gdData, aop); +#endif + } + + return S_OK; +} + +HRESULT DPNET_ReturnBuffer(DirectPlay8GlobalData *dp8gdData, + const DPNHANDLE hBufferHandle, + const DWORD dwFlags) +{ + HRESULT hr; + hr = IDirectPlay8ServiceProvider_ReturnBuffer(dp8gdData->sp, (void *)hBufferHandle, dwFlags); + return hr; +} + +HRESULT DPNET_GetApplicationDesc(DirectPlay8GlobalData *dp8gdData, + DPN_APPLICATION_DESC *const pAppDescBuffer, + DWORD *const pcbDataSize, + const DWORD dwFlags) +{ + EnterCriticalSection(&dp8gdData->cs_player); + + FIXME("return application desc\n"); + + LeaveCriticalSection(&dp8gdData->cs_player); + + return S_OK; +} + +HRESULT DPNET_SetPeerInfo(DirectPlay8GlobalData *dp8gdData, + const DPN_PLAYER_INFO *const pdpnPlayerInfo, + PVOID const pvAsyncContext, DPNHANDLE *const phAsyncHandle, + const DWORD dwFlags) +{ + dpPlayer *play = &dp8gdData->localPlayer; + + if (play->status != PLAYER_UNKNOWN) { + FIXME("change local info\n"); + return DPNSUCCESS_PENDING; + } + + DPNET_LockPlayer(dp8gdData, play); + + if (pdpnPlayerInfo->dwInfoFlags & DPNINFO_NAME) { + if (play->name) HeapFree(GetProcessHeap(), 0, play->name); + play->name = NULL; + if (pdpnPlayerInfo->pwszName) { + DWORD l = (strlenW(pdpnPlayerInfo->pwszName)+1)*sizeof(WCHAR); + play->name = HeapAlloc(GetProcessHeap(), 0, l); + memcpy(play->name, pdpnPlayerInfo->pwszName, l); + } + } + + if (pdpnPlayerInfo->dwInfoFlags & DPNINFO_DATA) { + if (play->data) HeapFree(GetProcessHeap(), 0, play->data); + play->data = NULL; + play->data_len = 0; + if (pdpnPlayerInfo->pvData && pdpnPlayerInfo->dwDataSize) { + play->data = HeapAlloc(GetProcessHeap(), 0, pdpnPlayerInfo->dwDataSize); + play->data_len = pdpnPlayerInfo->dwDataSize; + memcpy(play->data, pdpnPlayerInfo->pvData, pdpnPlayerInfo->dwDataSize); + } + } + + DPNET_UnlockPlayer(dp8gdData, play); + + return S_OK; +} + +HRESULT DPNET_GetPeerInfo(DirectPlay8GlobalData *dp8gdData, + const DPNID dpnid, + DPN_PLAYER_INFO *const pdpnPlayerInfo, + DWORD *const pdwSize, + const DWORD dwFlags) +{ + dpPlayer *play; + DWORD len; + + play = DPNET_FindPlayerByID(dp8gdData, dpnid); + if (!play) { + TRACE("player not found\n"); + return DPNERR_INVALIDPLAYER; + } + + DPNET_LockPlayer(dp8gdData, play); + + len = sizeof(DPN_PLAYER_INFO); + if (play->name) + len += (strlenW(play->name)+1)*sizeof(WCHAR); + if (play->data) + len += play->data_len; + + if (*pdwSize < len) { + *pdwSize = len; + DPNET_UnlockPlayer(dp8gdData, play); + return DPNERR_BUFFERTOOSMALL; + } + + if (pdpnPlayerInfo) { + LPBYTE ptr = (LPVOID)(pdpnPlayerInfo+1); + pdpnPlayerInfo->dwSize = sizeof(DPN_PLAYER_INFO); + pdpnPlayerInfo->dwInfoFlags = DPNINFO_NAME | DPNINFO_DATA; + pdpnPlayerInfo->dwPlayerFlags = 0; + if (play == &dp8gdData->localPlayer) { + pdpnPlayerInfo->dwPlayerFlags |= DPNPLAYER_LOCAL; + if (dp8gdData->is_host) + pdpnPlayerInfo->dwPlayerFlags |= DPNPLAYER_HOST; + } + if (play == dp8gdData->remoteHost) + pdpnPlayerInfo->dwPlayerFlags |= DPNPLAYER_HOST; + if (play->name) { + DWORD len = (strlenW(play->name)+1)*sizeof(WCHAR); + pdpnPlayerInfo->pwszName = (LPVOID)ptr; + memcpy(ptr, play->name, len); + ptr += len; + } else { + pdpnPlayerInfo->pwszName = NULL; + } + if (play->data) { + pdpnPlayerInfo->pvData = (LPVOID)ptr; + pdpnPlayerInfo->dwDataSize = play->data_len; + memcpy(ptr, play->data, play->data_len); + ptr += play->data_len; + } else { + pdpnPlayerInfo->pvData = NULL; + pdpnPlayerInfo->dwDataSize = 0; + } + } + + DPNET_UnlockPlayer(dp8gdData, play); + + return S_OK; +} + +HRESULT DPNET_GetPlayerContext(DirectPlay8GlobalData *dp8gdData, + const DPNID dpnid, + PVOID *const ppvPlayerContext, + const DWORD dwFlags) +{ + dpPlayer *play; + + play = DPNET_FindPlayerByID(dp8gdData, dpnid); + if (!play) { + TRACE("player not found\n"); + return DPNERR_INVALIDPLAYER; + } + + DPNET_LockPlayer(dp8gdData, play); + + /* FIXME: make sure CREATE_PLAYER is complete, + * return DPNERR_NOTREADY if not */ + + *ppvPlayerContext = play->pvPlayerContext; + + DPNET_UnlockPlayer(dp8gdData, play); + + return S_OK; +} + +HRESULT DPNET_EnumHosts(DirectPlay8GlobalData *dp8gdData, + PDPN_APPLICATION_DESC const pdnAppDesc, + IDirectPlay8Address *const pAddrHost, IDirectPlay8Address *const pDeviceInfo, + PVOID const pvUserEnumData, const DWORD dwUserEnumDataSize, + const DWORD dwEnumCount, const DWORD dwRetryInterval, + const DWORD dwTimeOut, PVOID const pvUserContext, + DPNHANDLE *const phAsyncHandle, const DWORD dwFlags) +{ + IDirectPlay8AddressImpl *addrImplDevice = (IDirectPlay8AddressImpl *)pDeviceInfo; + DPN_SP_CAPS dpnSPCaps; + DPNET_AsyncOp *aop; + DP8_EnumRequest *msg; + LPVOID msg_end; + BOOL has_guid; + + TRACE(" app dwFlags: 0x%08x\n", pdnAppDesc->dwFlags); + + DPNET_InitSP(dp8gdData, &addrImplDevice->guidSP); + + has_guid = !IsEqualGUID(&GUID_NULL, &pdnAppDesc->guidApplication); + + aop = DPNET_AsyncAlloc(dp8gdData, DPN_MSGID_ENUM_HOSTS_RESPONSE, sizeof(*msg) + has_guid*sizeof(GUID) + dwUserEnumDataSize); + aop->dwFlags = dwFlags; + aop->pvUserContext = pvUserContext; + if (pAddrHost) { + IDirectPlay8Address_AddRef(pAddrHost); + aop->pAddrHost = pAddrHost; + } + IDirectPlay8Address_AddRef(pDeviceInfo); + aop->pAddrDev = pDeviceInfo; + + msg = (LPVOID)aop->PackBuffer.pBufferData; + + msg->tag = DP8SESS_TAG; + msg->command = DP8SESS_ENUM_REQUEST; + msg->id = (DPNET_Random(dp8gdData) & 0xfff0) + 1; + msg->type = has_guid ? DP8SESS_ENUM_REQ_WITH_GUID : DP8SESS_ENUM_REQ_WITHOUT_GUID; + msg_end = msg+1; + + if (has_guid) { + memcpy(msg_end, &pdnAppDesc->guidApplication, sizeof(GUID)); + msg_end = ((GUID*)msg_end)+1; + } + + if (dwUserEnumDataSize) { + /* just copy to end of packet for now */ + memcpy(msg_end, pvUserEnumData, dwUserEnumDataSize); + } + + aop->dwID = msg->id; + + IDirectPlay8ServiceProvider_GetSPCaps(dp8gdData->sp, &dpnSPCaps, 0); + if (dwEnumCount) + aop->dwRetryLimit = dwEnumCount; + else + aop->dwRetryLimit = dpnSPCaps.dwDefaultEnumCount; + + if (dwRetryInterval) + aop->dwRetryInterval = dwRetryInterval; + else + aop->dwRetryInterval = dpnSPCaps.dwDefaultEnumRetryInterval; + + if (dwTimeOut) + aop->dwTimeOut = dwTimeOut; + else + aop->dwTimeOut = dpnSPCaps.dwDefaultEnumTimeout; + + if (dwFlags & DPNENUMHOSTS_SYNC) + DPNET_AsyncSetSync(dp8gdData, aop); + + DPNET_StartAsync(dp8gdData, aop); + + if (dwFlags & DPNENUMHOSTS_SYNC) { + DPNET_AsyncWait(dp8gdData, aop); + return DPNET_AsyncFree(dp8gdData, aop); + } else { + *phAsyncHandle = (DPNHANDLE)aop; + } + + return S_OK; +} + +HRESULT DPNET_Connect(DirectPlay8GlobalData *dp8gdData, + const DPN_APPLICATION_DESC *const pdnAppDesc, + IDirectPlay8Address *pAddrHost, + IDirectPlay8Address *pDeviceInfo, + const DPN_SECURITY_DESC * const pdnSecurity, + const DPN_SECURITY_CREDENTIALS *const pdnCredentials, + const void *const pvUserConnectData, + DWORD dwUserConnectDataSize, + void *pvPlayerContext, void *pvAsyncContext, + DPNHANDLE *phAsyncHandle, DWORD dwFlags) +{ + IDirectPlay8AddressImpl *addrImplDevice = (IDirectPlay8AddressImpl *)pDeviceInfo; + DPNET_AsyncOp *aop; + DP8_Connect *msg; + dpPlayer *play = &dp8gdData->localPlayer; + BOOL found; + + TRACE(" app dwFlags: 0x%08x\n", pdnAppDesc->dwFlags); + + DPNET_KillPlayers(dp8gdData); + + DPNET_SetAppDesc(dp8gdData, pdnAppDesc); + + DPNET_InitSP(dp8gdData, &addrImplDevice->guidSP); + + if (pdnSecurity || pdnCredentials) + FIXME("we dont support security stuff right now\n"); + + dp8gdData->pkt_id = 0; + + /* initialize local player */ + play->status = PLAYER_REQUEST_SENT; + play->pvPlayerContext = pvPlayerContext; + + if (dwUserConnectDataSize) { + play->conn_data = HeapAlloc(GetProcessHeap(), 0, dwUserConnectDataSize); + play->conn_data_len = dwUserConnectDataSize; + memcpy(play->conn_data, pvUserConnectData, dwUserConnectDataSize); + } + + /* initialize remote player (host) */ + play = DPNET_MakePlayer(dp8gdData, pAddrHost, &found); + dp8gdData->remoteHost = play; + play->status = PLAYER_REQUEST_SENT; + play->conn_id = DPNET_Random(dp8gdData); + + aop = DPNET_AsyncAlloc(dp8gdData, DPN_MSGID_CONNECT_COMPLETE, sizeof(*msg)); + aop->dwFlags = dwFlags; + aop->pvUserContext = pvAsyncContext; + if (pAddrHost) { + IDirectPlay8Address_AddRef(pAddrHost); + aop->pAddrHost = pAddrHost; + } + IDirectPlay8Address_AddRef(pDeviceInfo); + aop->pAddrDev = pDeviceInfo; + + msg = (LPVOID)aop->PackBuffer.pBufferData; + + msg->command = DP8SESS_CONNECT; + msg->type = DP8SESS_CONN_REQUEST; + msg->pkt = 0; + msg->ver = DP8SESS_DEFVER; + msg->id = play->conn_id; + msg->time = GetTickCount(); + + aop->dwID = play->conn_id; + + aop->dwRetryLimit = dp8gdData->dpnCaps.dwConnectRetries; + aop->dwRetryInterval = dp8gdData->dpnCaps.dwConnectTimeout; + + if (dwFlags & DPNCONNECT_SYNC) + DPNET_AsyncSetSync(dp8gdData, aop); + + DPNET_StartAsync(dp8gdData, aop); + + if (dwFlags & DPNCONNECT_SYNC) { + DPNET_AsyncWait(dp8gdData, aop); + return DPNET_AsyncFree(dp8gdData, aop); + } else { + *phAsyncHandle = (DPNHANDLE)aop; + } + + return DPNSUCCESS_PENDING; +} + +HRESULT DPNET_Host(DirectPlay8GlobalData *dp8gdData, + const DPN_APPLICATION_DESC *const pdnAppDesc, + IDirectPlay8Address **const prgpDeviceInfo, + const DWORD cDeviceInfo, + const DPN_SECURITY_DESC * const pdnSecurity, + const DPN_SECURITY_CREDENTIALS *const pdnCredentials, + void *pvPlayerContext, + const DWORD dwFlags) +{ + IDirectPlay8AddressImpl *addrImplDevice = (IDirectPlay8AddressImpl *)prgpDeviceInfo[0]; + DPNMSG_CREATE_PLAYER resp; + dpPlayer *play = &dp8gdData->localPlayer; + HRESULT hr; + + TRACE(" app dwFlags: 0x%08x\n", pdnAppDesc->dwFlags); + + DPNET_KillPlayers(dp8gdData); + + DPNET_SetAppDesc(dp8gdData, pdnAppDesc); + + DPNET_InitSP(dp8gdData, &addrImplDevice->guidSP); + + if (pdnSecurity || pdnCredentials) + FIXME("we dont support security stuff right now\n"); + + dp8gdData->pkt_id = 0; + + dp8gdData->is_host = TRUE; + + /* initialize local player (host) */ + play->status = PLAYER_ACTIVE; + play->pvPlayerContext = pvPlayerContext; + + play->dwPlayerID = 1; /* FIRST POST!!!11!one! */ + dp8gdData->player_id = 2; + dp8gdData->appdesc.dwCurrentPlayers = 1; + + memset(&resp, 0, sizeof(resp)); + resp.dwSize = sizeof(resp); + resp.dpnidPlayer = play->dwPlayerID; + resp.pvPlayerContext = play->pvPlayerContext; + TRACE("dispatching local CreatePlayer message\n"); + hr = dp8gdData->pfMessageHandler(dp8gdData->pvUserContext, DPN_MSGID_CREATE_PLAYER, &resp); + dp8gdData->localPlayer.pvPlayerContext = resp.pvPlayerContext; + TRACE("returned\n"); + + return S_OK; +} + +/**** FIXME: move this and related stuff to a separate file (transport.c?) ****/ + +HRESULT DPNET_SendTo(DirectPlay8GlobalData *dp8gdData, const DPNID dpnid, + const DPN_BUFFER_DESC *const pBufferDesc, const DWORD cBufferDesc, + const DWORD dwTimeOut, void *pvAsyncContext, + DPNHANDLE *const phAsyncHandle, const DWORD dwFlags) +{ + DPNET_AsyncOp *aop; + DP8_Data *msg; + dpPlayer *play = NULL; + DWORD c, len; + + if (dpnid == DPNID_ALL_PLAYERS_GROUP) { + /* just sending to first player for now... */ + play = dp8gdData->remotePlayers; + /* FIXME: to be able to send to more than one player + * and still only submit SEND_COMPLETE once, we'll + * probably need to change the AsyncOp structure. */ + + if (!(dwFlags & DPNSEND_NOLOOPBACK)) { + FIXME("dispatch loopback RECEIVE\n"); + } + + if (!play) { + /* we're alone, talking to ourselves */ + FIXME("no receiver, should still dispatch SEND_COMPLETE\n"); + return S_OK; + } + } else { + play = DPNET_FindPlayerByID(dp8gdData, dpnid); + + if (!play) return DPNERR_INVALIDPLAYER; + } + + len = 0; + for (c=0; cdwFlags = dwFlags; + aop->pvUserContext = (PVOID)pvAsyncContext; + if (play) { + IDirectPlay8Address_AddRef(play->pAddress); + aop->pAddrHost = play->pAddress; + } + aop->pAddrDev = NULL; + + msg = (LPVOID)aop->PackBuffer.pBufferData; + + DPNET_LockPlayer(dp8gdData, play); + + msg->command = (dwFlags & DPNSEND_GUARANTEED) ? DP8SESS_DATA_RELIABLE : DP8SESS_DATA_UNRELIABLE; + msg->type = 0x0; + msg->next_out = play->next_out++; + msg->next_in = play->next_in; + play->ack_in = play->next_in; + + aop->dwTimeOut = dwTimeOut; + aop->dwTimeSent = GetTickCount(); + + if (dwFlags & DPNSEND_NOCOPY) { + aop->cUserBuffer = cBufferDesc; + memcpy(&aop->UserBuffer, pBufferDesc, sizeof(DPN_BUFFER_DESC)*cBufferDesc); + } else { + LPBYTE pk = (LPVOID)(msg+1); + for (c=0; cdwID = msg->next_out; + aop->forget = TRUE; /* for now */ + + DPNET_UnlockPlayer(dp8gdData, play); + + if (dwFlags & DPNCONNECT_SYNC) + DPNET_AsyncSetSync(dp8gdData, aop); + + DPNET_StartAsync(dp8gdData, aop); + + if (dwFlags & DPNCONNECT_SYNC) { + DPNET_AsyncWait(dp8gdData, aop); + return DPNET_AsyncFree(dp8gdData, aop); + } else { + *phAsyncHandle = (DPNHANDLE)aop; + } + + return DPNSUCCESS_PENDING; +} diff --git a/dlls/dpnet/sp_tcpip.c b/dlls/dpnet/sp_tcpip.c new file mode 100644 index 0000000..24158be --- /dev/null +++ b/dlls/dpnet/sp_tcpip.c @@ -0,0 +1,613 @@ +/* dpnet.dll + * + * Copyright (C) 2002-2007 TransGaming Inc. + * Written by: David Hammerton, Ove Kåven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winreg.h" +#include "winnls.h" +#include "objbase.h" +#include "wine/debug.h" +#include "winerror.h" +#include "winsock2.h" +#include "wine/unicode.h" + +#include "dplay8.h" +#include "dplobby8.h" +#include "dplay8_private.h" +#include "dplay8sp.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dplay); + +static ICOM_VTABLE(IDirectPlay8ServiceProvider) directPlay8SP_TCPIPVT; + +void SP_TCPIP_ReleaseAddressData(PVOID data) +{ + HeapFree(GetProcessHeap(), 0, data); +} + +/* SHOULDNT NEED TO DUPLICATE. SHOULD USE URL */ +void SP_TCPIP_DuplicateAddressData(IDirectPlay8Address *pAddr, PVOID data) +{ + struct sockaddr_in *newData; + + newData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct sockaddr_in)); + + memcpy(newData, data, sizeof(struct sockaddr_in)); + DPNET_Address_SetSPData(pAddr, newData, SP_TCPIP_ReleaseAddressData, + SP_TCPIP_DuplicateAddressData); +} + +HRESULT WINAPI DirectPlay8SP_TCPIP_BuildAddressFromSPData(PDIRECTPLAY8SERVICEPROVIDER iface, + IDirectPlay8Address *pAddr, + PVOID pvSPData) +{ + /* ICOM_THIS(IDirectPlay8SP_TCPIPImpl, iface); */ + struct sockaddr_in *sin = pvSPData; + struct sockaddr_in *addrSPData; + char buf[16]; + WCHAR wbuf[16]; + DWORD port; + + TRACE("(%p)->(%p, %p)\n", iface, pAddr, pvSPData); + + /* FIXME: we could call IDirectPlay8AddressIP::BuildFromSockAddr, + * but it's not implemented yet */ + + /* FIXME: call getnameinfo() instead */ + sprintf(buf, "%d.%d.%d.%d", + sin->sin_addr.S_un.S_un_b.s_b1, + sin->sin_addr.S_un.S_un_b.s_b2, + sin->sin_addr.S_un.S_un_b.s_b3, + sin->sin_addr.S_un.S_un_b.s_b4); + MultiByteToWideChar(CP_ACP, 0, buf, -1, wbuf, 16); + port = ntohs(sin->sin_port); + + IDirectPlay8Address_Clear(pAddr); + IDirectPlay8Address_SetSP(pAddr, &CLSID_DP8SP_TCPIP); + IDirectPlay8Address_AddComponent(pAddr, DPNA_KEY_HOSTNAME, + wbuf, (strlenW(wbuf)+1)*sizeof(WCHAR), + DPNA_DATATYPE_STRING); + IDirectPlay8Address_AddComponent(pAddr, DPNA_KEY_PORT, + &port, sizeof(DWORD), + DPNA_DATATYPE_DWORD); + + addrSPData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct sockaddr_in)); + memcpy(addrSPData, pvSPData, sizeof(struct sockaddr_in)); + + DPNET_Address_SetSPData(pAddr, addrSPData, SP_TCPIP_ReleaseAddressData, + SP_TCPIP_DuplicateAddressData); + + return S_OK; +} + +static void SP_TCPIP_CallRead(void *pvIface, tpReadNode *node, DWORD sent) +{ + PDIRECTPLAY8SERVICEPROVIDER iface = pvIface; + ICOM_THIS(IDirectPlay8SP_TCPIPImpl, iface); + IDirectPlay8Address *pAddr = NULL; + IDirectPlay8Address *pUseAddr; + dpPlayer *play; + BOOL keep = FALSE; + + /* look for existing address object (from established connections) */ + EnterCriticalSection(&This->dp8gdData->cs_player); + play = This->dp8gdData->remotePlayers; + while (play) { + IDirectPlay8AddressImpl *addr = (IDirectPlay8AddressImpl *)play->pAddress; + if (IsEqualGUID(&addr->guidSP, &CLSID_DP8SP_TCPIP) && + !memcmp(addr->spData, node->Addr.pBufferData, node->Addr.dwBufferSize)) { + pAddr = play->pAddress; + IDirectPlay8Address_AddRef(pAddr); + break; + } + play = play->next; + } + LeaveCriticalSection(&This->dp8gdData->cs_player); + + pUseAddr = pAddr; + if (!pUseAddr) { + /* not found, build new one */ + DirectPlay8SP_TCPIP_BuildAddressFromSPData(iface, node->pAddr, node->Addr.pBufferData); + pUseAddr = node->pAddr; + } + + if (TRACE_ON(dplay)) { + BUFFERDESC buf; + buf.dwBufferSize = sent; + buf.pBufferData = node->Data.pBufferData; + DPNET_ParsePacket(IPPROTO_UDP, (LPVOID)node->Addr.pBufferData, NULL, &buf, 1); + /* debug_hexdump(node->Data.pBufferData, node->Data.dwBufferSize); */ + } + + if (This->msgCallback) { + keep = This->msgCallback(This->dp8gdData, node->Data.pBufferData, sent, pUseAddr); + } else { + TRACE("packet ignored\n"); + } + + if (pAddr) IDirectPlay8Address_Release(pAddr); + + node->Addr.dwBufferSize = sizeof(struct sockaddr_in); + if (keep) { + node->Data.pBufferData = HeapAlloc(GetProcessHeap(), 0, node->Data.dwBufferSize); + } +} + +static BOOL SP_TCPIP_InitRead(void *pvIface, tpReadNode *node) +{ + PDIRECTPLAY8SERVICEPROVIDER iface = pvIface; + ICOM_THIS(IDirectPlay8SP_TCPIPImpl, iface); + DWORD sent = 0; + DWORD flags = 0; + int res; + + TRACE("(%p, %p)\n", pvIface, node); + + memset(&node->ovl, 0, sizeof(node->ovl)); + node->ovl.hEvent = CreateEventA(NULL, FALSE, FALSE, NULL); + if (!node->ovl.hEvent) { + TRACE("could not create event\n"); + return FALSE; + } + node->Addr.dwBufferSize = sizeof(struct sockaddr_in); + node->Addr.pBufferData = HeapAlloc(GetProcessHeap(), 0, node->Addr.dwBufferSize); + node->Data.dwBufferSize = This->dwMaxSize; + node->Data.pBufferData = HeapAlloc(GetProcessHeap(), 0, node->Data.dwBufferSize); + DPNET_CreateDirectPlay8Address(NULL, &IID_IDirectPlay8Address, (LPVOID*)&node->pAddr); + IDirectPlay8Address_SetSP(node->pAddr, &CLSID_DP8SP_TCPIP); + while (TRUE) { + /* request some data */ + res = WSARecvFrom(This->socket, (LPWSABUF)&node->Data, 1, &sent, &flags, + (LPVOID)node->Addr.pBufferData, (LPINT)&node->Addr.dwBufferSize, + &node->ovl, NULL); + if (res < 0) { + int err = WSAGetLastError(); + switch (err) { + case WSA_IO_PENDING: + TRACE("=> WSA_IO_PENDING\n"); + return TRUE; + default: + TRACE("=> WSA error %d\n", err); + return FALSE; + } + } + /* got some already, process it */ + SP_TCPIP_CallRead(pvIface, node, sent); + } +} + +static BOOL SP_TCPIP_CompRead(void *pvIface, tpReadNode *node) +{ + PDIRECTPLAY8SERVICEPROVIDER iface = pvIface; + ICOM_THIS(IDirectPlay8SP_TCPIPImpl, iface); + DWORD sent = 0; + DWORD flags = 0; + int res; + + TRACE("(%p, %p)\n", pvIface, node); + + if (!WSAGetOverlappedResult(This->socket, &node->ovl, &sent, FALSE, &flags)) { + int err = WSAGetLastError(); + TRACE("=> WSA error %d\n", err); + return FALSE; + } + + while (TRUE) { + /* process data */ + SP_TCPIP_CallRead(pvIface, node, sent); + /* request some more */ + res = WSARecvFrom(This->socket, (LPWSABUF)&node->Data, 1, &sent, &flags, + (LPVOID)node->Addr.pBufferData, (LPINT)&node->Addr.dwBufferSize, + &node->ovl, NULL); + if (res < 0) { + int err = WSAGetLastError(); + switch (err) { + case WSA_IO_PENDING: + TRACE("=> WSA_IO_PENDING\n"); + return TRUE; + default: + TRACE("=> WSA error %d\n", err); + return FALSE; + } + } + } +} + +HRESULT WINAPI +DirectPlay8SP_TCPIP_ReturnBuffer(PDIRECTPLAY8SERVICEPROVIDER iface, + void *pk, DWORD dwFlags) +{ + /* ICOM_THIS(IDirectPlay8SP_TCPIPImpl, iface); */ + HeapFree(GetProcessHeap(), 0, pk); + return S_OK; +} + +HRESULT WINAPI +DirectPlay8SP_TCPIP_QueryInterface(PDIRECTPLAY8SERVICEPROVIDER iface, + REFIID riid, LPVOID *obj) +{ + ICOM_THIS(IDirectPlay8SP_TCPIPImpl, iface); + TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj); + if (IsEqualGUID(&IID_IUnknown, riid) || + IsEqualGUID(&IID_IDirectPlay8ServiceProvider, riid)) + { + This->ref++; + *obj = This; + return S_OK; + } + else + { + FIXME("(%p)->(%s, %p): no interface\n", iface, debugstr_guid(riid), obj); + return E_NOINTERFACE; + } +} + +ULONG WINAPI +DirectPlay8SP_TCPIP_AddRef(PDIRECTPLAY8SERVICEPROVIDER iface) +{ + ICOM_THIS(IDirectPlay8SP_TCPIPImpl, iface); + TRACE("(%p)->()\n", iface); + return ++This->ref; +} + +ULONG WINAPI +DirectPlay8SP_TCPIP_Release(PDIRECTPLAY8SERVICEPROVIDER iface) +{ + ICOM_THIS(IDirectPlay8SP_TCPIPImpl, iface); + TRACE("(%p)->()\n", iface); + if (--This->ref) return This->ref; + + FIXME("destroy this and everything\n"); + closesocket(This->socket); + + if (This->threadPool) + IDirectPlay8ThreadPool_Release(This->threadPool); + + HeapFree(GetProcessHeap(), 0, This); + return 0; +} + +HRESULT WINAPI +DirectPlay8SP_TCPIP_Initialize(PDIRECTPLAY8SERVICEPROVIDER iface, + DirectPlay8GlobalData *dp8gdData, + spMessageReceived msgCallback, + const DWORD dwFlags) +{ + ICOM_THIS(IDirectPlay8SP_TCPIPImpl, iface); + HRESULT hr; + struct sockaddr_in bind_sin; + int bind_err, port; + + WORD version = MAKEWORD(2, 2); + WSADATA wsaData; + + /* fixme: error checking, and much more */ + TRACE("(%p)->(%p, %p, 0x%08x)\n", iface, dp8gdData, msgCallback, dwFlags); + + This->dpnSPCaps.dwFlags = DPNSPCAPS_SUPPORTSALLADAPTERS; + This->dpnSPCaps.dwNumThreads = 4; /* windows: 3 */ + This->dpnSPCaps.dwDefaultEnumCount = 5; + This->dpnSPCaps.dwDefaultEnumRetryInterval = 1500; + This->dpnSPCaps.dwDefaultEnumTimeout = 1500; + This->dpnSPCaps.dwMaxEnumPayloadSize = 0; /* windows: 983 */ + This->dpnSPCaps.dwBuffersPerThread = 0; /* windows: 1 */ + This->dpnSPCaps.dwSystemBufferSize = 0; /* windows: 8192 */ + + + This->dp8gdData = dp8gdData; + This->msgCallback = msgCallback; + + WSAStartup(version, &wsaData); + This->dwMaxSize = wsaData.iMaxUdpDg; + This->socket = socket(AF_INET, SOCK_DGRAM, 0); + + TRACE("got socket: %p\n", This->socket); + + port = 2302; + do + { + bind_sin.sin_port = htons(2302); + bind_sin.sin_family = AF_INET; + bind_sin.sin_addr.s_addr = INADDR_ANY; + bind_err = bind(This->socket, (struct sockaddr *)&bind_sin, sizeof(bind_sin)); + port++; + } while (bind_err < 0 && port < 2400); + if (bind_err < 0) + FIXME("couldn't bind to a port, something could go wrong, maybe...\n"); + + hr = DPNET_GetThreadPool(&This->threadPool, This->dpnSPCaps.dwNumThreads); + if (FAILED(hr)) { + ERR("couldn't initialize thread pool: 0x%08x\n", hr); + return hr; + } + DPNET_InitAsyncRead(This->threadPool, SP_TCPIP_InitRead, SP_TCPIP_CompRead, This); + + return S_OK; +} + +static HRESULT SP_TCPIP_SetAddrDataFromHostname(PDIRECTPLAY8ADDRESS dp8Address, + WCHAR *pHostName, DWORD port) +{ + char *ahostname, *portpos; + int lenhostname; + struct sockaddr_in *addrSPData; + + TRACE("(%p, %s)\n", dp8Address, debugstr_w(pHostName)); + + lenhostname = strlenW(pHostName)+1; + ahostname = (CHAR *)HeapAlloc(GetProcessHeap(), 0, lenhostname * sizeof(char)); + WideCharToMultiByte(CP_ACP, -1, pHostName, -1, ahostname, lenhostname, + NULL, NULL); + if ((portpos = strchr(ahostname, ':'))) + { + *portpos = '\0'; + portpos += 1; + FIXME("support custom ports in hostname\n"); + } + if (!port) port = 2302; + + addrSPData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct sockaddr_in)); + addrSPData->sin_port = htons(port); + addrSPData->sin_family = AF_INET; + + if ((addrSPData->sin_addr.s_addr = inet_addr(ahostname)) == INADDR_NONE) + { + struct hostent *host_ip; + if (!(host_ip = gethostbyname(ahostname)) || !host_ip->h_addr_list[0]) + { + ERR("host name invalid. what do we do??\n"); + return E_FAIL; + } + + addrSPData->sin_addr.s_addr = inet_addr(host_ip->h_addr_list[0]); + } + HeapFree(GetProcessHeap(), 0, ahostname); + DPNET_Address_SetSPData(dp8Address, addrSPData, SP_TCPIP_ReleaseAddressData, + SP_TCPIP_DuplicateAddressData); + return S_OK; +} + +/* no. this isn't quite right. We need a packet window like thing - and that thread should + * prompt for the address. Currently multiple threads can try to send things at once, + * this causes a problem in that multiple dialogs could come up at once. + * We get around this by grabbing a lock before testing the service provider. + * it is a HACK (David, 23/01/03) - but until we get some better packet management, it will + * have to do + */ +static HRESULT SP_TCPIP_GetSockAddress(PDIRECTPLAY8ADDRESS dp8Address, + struct sockaddr_in *sin) +{ + struct sockaddr_in *addrSPData; + + TRACE("(%p, %p)\n", dp8Address, sin); + + DPNET_Address_GetDialogLock(dp8Address); + DPNET_Address_GetSPData(dp8Address, (void **)&addrSPData); + if (!addrSPData) + { /* FIXME: all this should probably be somewhere else.. */ + WCHAR *hostname = NULL; + DWORD size = 0; + DWORD type = 0; + DWORD port = 0; + + if (IDirectPlay8Address_GetComponentByName(dp8Address, DPNA_KEY_HOSTNAME, + NULL, &size, &type) == DPNERR_BUFFERTOOSMALL + && size != 0) + { + DWORD portsize = sizeof(DWORD); + hostname = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR) * size); + IDirectPlay8Address_GetComponentByName(dp8Address, DPNA_KEY_HOSTNAME, + hostname, &size, &type); + /* type should be DPNA_DATATYPE_STRING*/ + + if (IDirectPlay8Address_GetComponentByName(dp8Address, DPNA_KEY_PORT, + &port, &portsize, &type) != S_OK) + port = 0; + } + else /* need to prompt for hostname */ + { + DPNET_HostNameShowDialog(&hostname); + + if (!hostname) + { + WARN("no host name specified\n"); + DPNET_Address_ReleaseDialogLock(dp8Address); + return E_FAIL; + } + TRACE("hostname from dialog: %s\n", debugstr_w(hostname)); + } + + if (FAILED(SP_TCPIP_SetAddrDataFromHostname(dp8Address, hostname, port))) + { + if (size) + HeapFree(GetProcessHeap(), 0, hostname); + DPNET_Address_ReleaseDialogLock(dp8Address); + return E_FAIL; + } + DPNET_Address_GetSPData(dp8Address, (void **)&addrSPData); + + if (size) + { + HeapFree(GetProcessHeap(), 0, hostname); + } + else + { + DPNET_HostNameFree(hostname); + } + } + memcpy(sin, addrSPData, sizeof(struct sockaddr_in)); + DPNET_Address_ReleaseDialogLock(dp8Address); + + return S_OK; +} + +HRESULT WINAPI DirectPlay8SP_TCPIP_SendTo(PDIRECTPLAY8SERVICEPROVIDER iface, + IDirectPlay8Address *pAddrDest, + const DPN_BUFFER_DESC *prgBufferDesc, + const DWORD cBufferDesc, + DWORD dwFlags) +{ + ICOM_THIS(IDirectPlay8SP_TCPIPImpl, iface); + struct sockaddr_in sin; + DWORD sent = 0; + HRESULT hr; + int res; + + TRACE("(%p)->(%p, %p, %i, %08x)\n", iface, pAddrDest, prgBufferDesc, cBufferDesc, dwFlags); + + hr = SP_TCPIP_GetSockAddress(pAddrDest, &sin); + if (hr != S_OK) + return hr; + + if (TRACE_ON(dplay)) { + DWORD c; + DPNET_ParsePacket(IPPROTO_UDP, NULL, &sin, prgBufferDesc, cBufferDesc); + for (c=0; csocket, (LPWSABUF)prgBufferDesc, cBufferDesc, + &sent, 0, (LPVOID)&sin, sizeof(sin), NULL, NULL); + if (res < 0) { + int err = WSAGetLastError(); + switch (err) { + case WSAEWOULDBLOCK: + TRACE("=> WSAEWOULDBLOCK\n"); + return DPNERR_NOTREADY; + default: + TRACE("=> WSA error %d\n", err); + return DPNERR_GENERIC; + } + } else { + TRACE("sent %d bytes\n", sent); + return DPN_OK; + } +} + +HRESULT WINAPI DirectPlay8SP_TCPIP_GetSPCaps(PDIRECTPLAY8SERVICEPROVIDER iface, + DPN_SP_CAPS *pdpnSPCaps, + DWORD dwFlags) +{ + ICOM_THIS(IDirectPlay8SP_TCPIPImpl, iface); + + TRACE("(%p)->(%p, 0x%08x)\n", iface, pdpnSPCaps, dwFlags); + pdpnSPCaps->dwFlags = This->dpnSPCaps.dwFlags; + pdpnSPCaps->dwNumThreads = This->dpnSPCaps.dwNumThreads; + pdpnSPCaps->dwDefaultEnumCount = This->dpnSPCaps.dwDefaultEnumCount; + pdpnSPCaps->dwDefaultEnumRetryInterval = This->dpnSPCaps.dwDefaultEnumRetryInterval; + pdpnSPCaps->dwDefaultEnumTimeout = This->dpnSPCaps.dwDefaultEnumTimeout; + pdpnSPCaps->dwMaxEnumPayloadSize = This->dpnSPCaps.dwMaxEnumPayloadSize; + pdpnSPCaps->dwBuffersPerThread = This->dpnSPCaps.dwBuffersPerThread; + pdpnSPCaps->dwSystemBufferSize = This->dpnSPCaps.dwSystemBufferSize; + + return S_OK; +} + +HRESULT WINAPI DirectPlay8SP_TCPIP_SetSPAddressData(PDIRECTPLAY8SERVICEPROVIDER iface, + IDirectPlay8Address *pAddr) +{ +/* ICOM_THIS(IDirectPlay8SP_TCPIPImpl, iface); */ + WCHAR *hostname = NULL; + DWORD port = 0; + WCHAR port_str[20]; /* enough for a DWORD (port) */ + + WCHAR *fullHostname, *p; + + DWORD bufferLen = 0; + DWORD data_type = 0; + HRESULT hr; + + TRACE("(%p)->(%p)\n", iface, pAddr); + + /* get hostname */ + hr = IDirectPlay8Address_GetComponentByName(pAddr, DPNA_KEY_HOSTNAME, + NULL, &bufferLen, &data_type); + if (hr != DPNERR_BUFFERTOOSMALL) return hr; + if (data_type != DPNA_DATATYPE_STRING) + ERR("wrong data type for host name\n"); + hostname = HeapAlloc(GetProcessHeap(), 0, bufferLen * sizeof(WCHAR)); + IDirectPlay8Address_GetComponentByName(pAddr, DPNA_KEY_HOSTNAME, + hostname, &bufferLen, &data_type); + + /* get port */ + bufferLen = 0; + hr = IDirectPlay8Address_GetComponentByName(pAddr, DPNA_KEY_PORT, + &port, &bufferLen, &data_type); + if (SUCCEEDED(hr) && data_type == DPNA_DATATYPE_DWORD) + { + const WCHAR fmt[] = {'%', 'l', 'd', 0}; + wsprintfW(port_str, fmt, port); + } + else if (hr != DPNERR_DOESNOTEXIST) + ERR("failed due to some other reason (bad)\n"); + + bufferLen = strlenW(hostname) + (port ? strlenW(port_str) : 0) + 2; + + fullHostname = HeapAlloc(GetProcessHeap(), 0, bufferLen * sizeof(WCHAR)); + strcpyW(fullHostname, hostname); + p = fullHostname + strlenW(hostname); + *p = (WCHAR) ':'; + p++; + if (port) strcpyW(p, port_str); + TRACE("full host name from address: %s\n", debugstr_w(fullHostname)); + + SP_TCPIP_SetAddrDataFromHostname(pAddr, fullHostname, 0); + HeapFree(GetProcessHeap(), 0, hostname); + HeapFree(GetProcessHeap(), 0, fullHostname); + return S_OK; +} + +static ICOM_VTABLE(IDirectPlay8ServiceProvider) directPlay8SP_TCPIPVT = +{ + DirectPlay8SP_TCPIP_QueryInterface, + DirectPlay8SP_TCPIP_AddRef, + DirectPlay8SP_TCPIP_Release, + DirectPlay8SP_TCPIP_Initialize, + DirectPlay8SP_TCPIP_SendTo, + (void*)0xdead1055, + DirectPlay8SP_TCPIP_GetSPCaps, + DirectPlay8SP_TCPIP_SetSPAddressData, + DirectPlay8SP_TCPIP_BuildAddressFromSPData, + DirectPlay8SP_TCPIP_ReturnBuffer +}; + +HRESULT DPNET_CreateDirectPlay8SP_TCPIP(IUnknown *pOuter, REFIID riid, LPVOID *ppobj) +{ + IDirectPlay8SP_TCPIPImpl *ipDP8SP_TCPIP; + HRESULT hr; + TRACE("()\n"); + ipDP8SP_TCPIP = (IDirectPlay8SP_TCPIPImpl *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(IDirectPlay8SP_TCPIPImpl)); + if (ipDP8SP_TCPIP == NULL) return E_OUTOFMEMORY; + ICOM_VTBL(ipDP8SP_TCPIP) = &directPlay8SP_TCPIPVT; + DirectPlay8SP_TCPIP_AddRef((IDirectPlay8ServiceProvider *)ipDP8SP_TCPIP); + TRACE("Created new object: %p\n", ipDP8SP_TCPIP); + hr = DirectPlay8SP_TCPIP_QueryInterface((IDirectPlay8ServiceProvider *)ipDP8SP_TCPIP, riid, ppobj); + DirectPlay8SP_TCPIP_Release((IDirectPlay8ServiceProvider *)ipDP8SP_TCPIP); + if (SUCCEEDED(hr)) + return S_OK; + else + return E_NOINTERFACE; +} diff --git a/dlls/dpnet/threadpool.c b/dlls/dpnet/threadpool.c new file mode 100644 index 0000000..5656664 --- /dev/null +++ b/dlls/dpnet/threadpool.c @@ -0,0 +1,407 @@ +/* dpnet.dll + * + * Copyright (C) 2002-2007 TransGaming Inc. + * Written by: David Hammerton, Ove Kåven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winreg.h" +#include "objbase.h" +#include "wine/debug.h" +#include "winerror.h" +#include "winsock2.h" + +#include "dplay8.h" +#include "dplobby8.h" +#include "dplay8_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dplay); + +static ICOM_VTABLE(IDirectPlay8ThreadPool) directPlay8ThreadPoolVT; + +static IDirectPlay8ThreadPoolImpl *pThreadPool; + +static void DPNET_UpdateTimer(IDirectPlay8ThreadPoolImpl *This) +{ + EnterCriticalSection(&This->cs_timer); + CancelWaitableTimer(This->hTimer); + /* FIXME */ + LeaveCriticalSection(&This->cs_timer); +} + +static DWORD CALLBACK DPNET_ThreadProc(LPVOID arg) +{ + IDirectPlay8ThreadPoolImpl *This = pThreadPool; + tpThreadNode *node = arg; + HANDLE hTimer = This->hTimer; + HANDLE *objs = NULL; + DWORD count = 0, res; + BOOL recount = TRUE; + + EnterCriticalSection(&node->cs); + node->dwID = GetCurrentThreadId(); + + for (;;) { + tpReadNode *rnode; + + if (recount) { + /* init and count objects */ + count = 2; + rnode = node->Read; + while (rnode) { + /* not-so-elegant way of calling init routine once... */ + if (rnode->pfnInit) { + rnode->pfnInit(rnode->ctx, rnode); + rnode->pfnInit = NULL; + } + if (rnode->ovl.hEvent) count++; + rnode = rnode->next; + } + /* make array of objects */ + objs = HeapReAlloc(GetProcessHeap(), 0, objs, count*sizeof(HANDLE)); + objs[0] = node->hJob; + objs[1] = hTimer; + count = 2; + rnode = node->Read; + while (rnode) { + if (rnode->ovl.hEvent) objs[count++] = rnode->ovl.hEvent; + rnode = rnode->next; + } + recount = FALSE; + } + LeaveCriticalSection(&node->cs); + + /* start waiting */ + res = WaitForMultipleObjects(count, objs, FALSE, INFINITE); + + EnterCriticalSection(&node->cs); + + if (res == WAIT_OBJECT_0) { + if (node->die_please) break; + recount = TRUE; + } + else if (res == WAIT_OBJECT_0+1) { + /* FIXME: check timeouts */ + DPNET_UpdateTimer(This); + } + else if (res == WAIT_FAILED) { + ERR("wait failed\n"); + } + else { + HANDLE hObj = objs[res - WAIT_OBJECT_0]; + /* find which object got it */ + rnode = node->Read; + while (rnode) { + if (rnode->ovl.hEvent == hObj) break; + rnode = rnode->next; + } + if (rnode) { + /* ah hah */ + rnode->pfnRead(rnode->ctx, rnode); + } + else { + ERR("failed to locate object for handle %p\n", hObj); + } + } + } + + /* cleanup */ + while (node->Read) { + tpReadNode *rnode = node->Read; + node->Read = rnode->next; + if (rnode->ovl.hEvent) CloseHandle(rnode->ovl.hEvent); + if (rnode->Addr.pBufferData) HeapFree(GetProcessHeap(), 0, rnode->Addr.pBufferData); + if (rnode->Data.pBufferData) HeapFree(GetProcessHeap(), 0, rnode->Data.pBufferData); + if (rnode->pAddr) IDirectPlay8Address_Release(rnode->pAddr); + HeapFree(GetProcessHeap(), 0, rnode); + } + LeaveCriticalSection(&node->cs); + return 0; +} + +static void DPNET_StartThreads(IDirectPlay8ThreadPool *iface) +{ + ICOM_THIS(IDirectPlay8ThreadPoolImpl, iface); + EnterCriticalSection(&This->cs_thread); + if (This == pThreadPool) { + while (This->dwCurThreads < This->dwNumThreads) { + tpThreadNode *node = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(tpThreadNode)); + InitializeCriticalSection(&node->cs); + node->hJob = CreateEventA(NULL, FALSE, FALSE, NULL); + node->next = This->threads; + if (node->next) node->next->prev = node; + This->threads = node; + node->hThread = CreateThread(NULL, 0, DPNET_ThreadProc, node, 0, NULL); + This->dwCurThreads++; + } + } + LeaveCriticalSection(&This->cs_thread); + DPNET_UpdateTimer(This); +} + +static void DPNET_StopThreads(IDirectPlay8ThreadPool *iface) +{ + ICOM_THIS(IDirectPlay8ThreadPoolImpl, iface); + EnterCriticalSection(&This->cs_thread); + if (This == pThreadPool) { + while (This->dwCurThreads) { + tpThreadNode *node = This->threads; + node->die_please = TRUE; + SetEvent(node->hJob); + WaitForSingleObject(node->hThread, INFINITE); + This->threads = node->next; + CloseHandle(node->hThread); + CloseHandle(node->hJob); + DeleteCriticalSection(&node->cs); + HeapFree(GetProcessHeap(), 0, node); + This->dwCurThreads--; + } + } + CancelWaitableTimer(This->hTimer); + LeaveCriticalSection(&This->cs_thread); +} + +/* IDirectPlay8ThreadPool */ +HRESULT WINAPI +DirectPlay8ThreadPool_QueryInterface(PDIRECTPLAY8THREADPOOL iface, + REFIID riid, LPVOID *obj) +{ + ICOM_THIS(IDirectPlay8ThreadPoolImpl, iface); + TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj); + if (IsEqualGUID(&IID_IUnknown, riid) || + IsEqualGUID(&IID_IDirectPlay8ThreadPool, riid)) + { + This->ref++; + *obj = This; + return S_OK; + } +#if 0 + else if (IsEqualGUID(&IID_IDirectPlay8ThreadPool_Internal, riid)) + { + This->ref++; + *obj = (LPVOID *)&This->lpVtbl2; + return S_OK; + } +#endif + else + { + FIXME("(%p)->(%s, %p): no interface\n", iface, debugstr_guid(riid), obj); + return E_NOINTERFACE; + } +} + +ULONG WINAPI +DirectPlay8ThreadPool_AddRef(PDIRECTPLAY8THREADPOOL iface) +{ + ICOM_THIS(IDirectPlay8ThreadPoolImpl, iface); + TRACE("(%p)->()\n", iface); + return ++This->ref; +} + +ULONG WINAPI +DirectPlay8ThreadPool_Release(PDIRECTPLAY8THREADPOOL iface) +{ + ICOM_THIS(IDirectPlay8ThreadPoolImpl, iface); + TRACE("(%p)->()\n", iface); + if (--This->ref) return This->ref; + + IDirectPlay8ThreadPool_Close(iface, 0); + + CloseHandle(This->hTimer); + DeleteCriticalSection(&This->cs_timer); + DeleteCriticalSection(&This->cs_thread); + HeapFree(GetProcessHeap(), 0, This); + return 0; +} + +HRESULT WINAPI +DirectPlay8ThreadPool_Initialize(PDIRECTPLAY8THREADPOOL iface, + PVOID const pvUserContext, + const PFNDPNMESSAGEHANDLER pfn, + const DWORD dwFlags) +{ + ICOM_THIS(IDirectPlay8ThreadPoolImpl, iface); + TRACE("(%p)->(%p, %p, %08x): stub\n", iface, pvUserContext, pfn, dwFlags); + if (pThreadPool) { + /* we should return DPNERR_NOTALLOWED if it was + * initialized by another dplay object? */ + TRACE("=> already initialized\n"); + return DPNERR_ALREADYINITIALIZED; + } + This->pfn = pfn; + This->pvUserContext = pvUserContext; + pThreadPool = This; + return S_OK; +} + +HRESULT WINAPI +DirectPlay8ThreadPool_Close(PDIRECTPLAY8THREADPOOL iface, + const DWORD dwFlags) +{ + ICOM_THIS(IDirectPlay8ThreadPoolImpl, iface); + FIXME("(%p)->(%08x): stub\n", iface, dwFlags); + if (pThreadPool != This) { + TRACE("=> not initialized\n"); + return DPNERR_UNINITIALIZED; + } + DPNET_StopThreads(iface); + if (pThreadPool == This) + pThreadPool = NULL; + return S_OK; +} + +HRESULT WINAPI +DirectPlay8ThreadPool_GetThreadCount(PDIRECTPLAY8THREADPOOL iface, + const DWORD dwProcessorNum, + DWORD *const pdwNumThreads, + const DWORD dwFlags) +{ + ICOM_THIS(IDirectPlay8ThreadPoolImpl, iface); + FIXME("(%p)->(%08i, %p, %08x): semi-stub\n", + iface, dwProcessorNum, pdwNumThreads, dwFlags); + if (pThreadPool != This) { + TRACE("=> not initialized\n"); + return DPNERR_UNINITIALIZED; + } + *pdwNumThreads = This->dwNumThreads; + return S_OK; +} + +HRESULT WINAPI +DirectPlay8ThreadPool_SetThreadCount(PDIRECTPLAY8THREADPOOL iface, + const DWORD dwProcessorNum, + const DWORD dwNumThreads, + const DWORD dwFlags) +{ + ICOM_THIS(IDirectPlay8ThreadPoolImpl, iface); + FIXME("(%p)->(%08i, %08i, %08x): semi-stub\n", + iface, dwProcessorNum, dwNumThreads, dwFlags); + if (pThreadPool != This) { + TRACE("=> not initialized\n"); + return DPNERR_UNINITIALIZED; + } + This->dwNumThreads = dwNumThreads; + DPNET_StartThreads(iface); + return S_OK; +} + +HRESULT WINAPI +DirectPlay8ThreadPool_DoWork(PDIRECTPLAY8THREADPOOL iface, + const DWORD dwAllowedTimeSlice, + const DWORD dwFlags) +{ + ICOM_THIS(IDirectPlay8ThreadPoolImpl, iface); + FIXME("(%p)->(%08i, %08x): stub (if they are using this expect badness, app may not be thread safe when we need it to be)\n", + iface, dwAllowedTimeSlice, dwFlags); + if (pThreadPool != This) { + TRACE("=> not initialized\n"); + return DPNERR_UNINITIALIZED; + } + return S_OK; +} + +static ICOM_VTABLE(IDirectPlay8ThreadPool) directPlay8ThreadPoolVT = +{ + DirectPlay8ThreadPool_QueryInterface, + DirectPlay8ThreadPool_AddRef, + DirectPlay8ThreadPool_Release, + DirectPlay8ThreadPool_Initialize, + DirectPlay8ThreadPool_Close, + DirectPlay8ThreadPool_GetThreadCount, + DirectPlay8ThreadPool_SetThreadCount, + DirectPlay8ThreadPool_DoWork +}; + +HRESULT DPNET_CreateDirectPlay8ThreadPool(IUnknown *pOuter, REFIID riid, LPVOID *ppobj) +{ + IDirectPlay8ThreadPoolImpl *ipDP8TP; + HRESULT hr; + TRACE("()\n"); + ipDP8TP = (IDirectPlay8ThreadPoolImpl *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(IDirectPlay8ThreadPoolImpl)); + if (ipDP8TP == NULL) return E_OUTOFMEMORY; + ICOM_VTBL(ipDP8TP) = &directPlay8ThreadPoolVT; +#if 0 + ipDP8TP->lpVtbl2 = &directPlay8ThreadPool_InternalVT; +#endif + InitializeCriticalSection(&ipDP8TP->cs_thread); + InitializeCriticalSection(&ipDP8TP->cs_timer); + ipDP8TP->hTimer = CreateWaitableTimerA(NULL, FALSE, NULL); + IDirectPlay8ThreadPool_AddRef((PDIRECTPLAY8THREADPOOL)ipDP8TP); + TRACE("Created new object: %p\n", ipDP8TP); + hr = IDirectPlay8ThreadPool_QueryInterface((PDIRECTPLAY8THREADPOOL)ipDP8TP, riid, ppobj); + IDirectPlay8ThreadPool_Release((PDIRECTPLAY8THREADPOOL)ipDP8TP); + if (SUCCEEDED(hr)) + return S_OK; + else + return E_NOINTERFACE; +} + +HRESULT DPNET_GetThreadPool(IDirectPlay8ThreadPool **ppThreadPool, DWORD dwNumThreads) +{ + IDirectPlay8ThreadPool* pTP; + if (!pThreadPool) { + /* thread pool does not exist, create one */ + HRESULT hr = DPNET_CreateDirectPlay8ThreadPool(NULL, &IID_IDirectPlay8ThreadPool, (LPVOID*)&pTP); + if (FAILED(hr)) + return hr; + hr = IDirectPlay8ThreadPool_Initialize(pTP, NULL, NULL, 0); + if (SUCCEEDED(hr)) + hr = IDirectPlay8ThreadPool_SetThreadCount(pTP, -1, dwNumThreads, 0); + if (SUCCEEDED(hr)) { + *ppThreadPool = pTP; + return S_OK; + } + IDirectPlay8ThreadPool_Release(pTP); + return hr; + } else { + /* thread pool already exist */ + pTP = (LPVOID)pThreadPool; + *ppThreadPool = pTP; + IDirectPlay8ThreadPool_AddRef(pTP); + return S_OK; + } +} + +/* This schedules async reads on *all* threads, so that multiple incoming packets + * can be processed in parallel. I think real dplay distributes its connections + * across the available threads to avoid overloading any of them, but I doubt we're + * going to have many enough connections for that to be an issue. */ +void DPNET_InitAsyncRead(IDirectPlay8ThreadPool *iface, tpInitFunc pfnInit, tpReadFunc pfnRead, void *data) +{ + ICOM_THIS(IDirectPlay8ThreadPoolImpl, iface); + EnterCriticalSection(&This->cs_thread); + if (This == pThreadPool) { + tpThreadNode *node = This->threads; + while (node) { + tpReadNode *rnode = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(tpReadNode)); + rnode->ctx = data; + rnode->pfnInit = pfnInit; + rnode->pfnRead = pfnRead; + rnode->next = node->Read; + if (rnode->next) rnode->next->prev = rnode; + node->Read = rnode; + SetEvent(node->hJob); + node = node->next; + } + } + LeaveCriticalSection(&This->cs_thread); +} diff --git a/dlls/dpnet/version.rc b/dlls/dpnet/version.rc index b6a8488..91ce570 100644 --- a/dlls/dpnet/version.rc +++ b/dlls/dpnet/version.rc @@ -1,26 +1,9 @@ -/* - * Copyright 2004 Raphael Junqueira - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#define WINE_FILEDESCRIPTION_STR "Wine DirectPlay 8" -#define WINE_FILENAME_STR "dpnet.dll" #define WINE_FILEVERSION 5,3,0,900 -#define WINE_FILEVERSION_STR "5.3.0.900" #define WINE_PRODUCTVERSION 5,3,0,900 -#define WINE_PRODUCTVERSION_STR "5.3" +#define WINE_FILEDESCRIPTION_STR "Cedega DirectPlay" +#define WINE_FILENAME_STR "dpnet.dll" +#define WINE_PRODUCTVERSION_STR "5.3.0000000.900" +#define WINE_PRODUCTNAME_STR "TransGaming Cedega" +#define WINE_FILEVERSION_STR "5.3.0000000.900 built by: Cedega" #include "wine/wine_common_ver.rc" diff --git a/dlls/uuid/uuid.c b/dlls/uuid/uuid.c index 4e9be90..6182f22 100644 --- a/dlls/uuid/uuid.c +++ b/dlls/uuid/uuid.c @@ -68,6 +68,9 @@ DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); #include "htiframe.h" #include "urlhist.h" #include "hlguids.h" +#include "dplay8.h" +#include "dpaddr.h" +#include "dplobby8.h" /* FIXME: cguids declares GUIDs but does not define their values */ @@ -79,6 +82,8 @@ DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); DEFINE_GUID(IID_IDirectPlaySP,0xc9f6360,0xcc61,0x11cf,0xac,0xec,0x00,0xaa,0x00,0x68,0x86,0xe3); DEFINE_GUID(IID_ISFHelper,0x1fe68efb,0x1874,0x9812,0x56,0xdc,0x00,0x00,0x00,0x00,0x00,0x00); DEFINE_GUID(IID_IDPLobbySP,0x5a4e5a20,0x2ced,0x11d0,0xa8,0x89,0x00,0xa0,0xc9,0x05,0x43,0x3c); +DEFINE_GUID(IID_IDirectPlay8ThreadPool_Internal,0x12f40839,0xe7a3,0x399b,0xab,0x45,0x9e,0x43,0x3d,0x8b,0x31,0x96); +DEFINE_GUID(IID_IDirectPlay8ServiceProvider,0x985e2c76,0x66bc,0x4d66,0xad,0x8e,0xed,0x38,0x1,0xf1,0xb4,0x59); DEFINE_GUID(FMTID_SummaryInformation,0xF29F85E0,0x4FF9,0x1068,0xAB,0x91,0x08,0x00,0x2B,0x27,0xB3,0xD9); DEFINE_GUID(FMTID_DocSummaryInformation,0xD5CDD502,0x2E9C,0x101B,0x93,0x97,0x08,0x00,0x2B,0x2C,0xF9,0xAE); diff --git a/include/dpaddr.h b/include/dpaddr.h index 8300729..240571b 100644 --- a/include/dpaddr.h +++ b/include/dpaddr.h @@ -21,13 +21,13 @@ #include #include +#include #ifdef __cplusplus extern "C" { #endif /* defined(__cplusplus) */ typedef REFIID DPNAREFIID; -typedef struct sockaddr SOCKADDR; /***************************************************************************** * DirectPlay8Addr defines @@ -56,6 +56,8 @@ typedef struct sockaddr SOCKADDR; #define DPNA_KEY_FLOWCONTROL_A "flowcontrol" #define DPNA_KEY_HOSTNAME_A "hostname" #define DPNA_KEY_NAMEINFO_A "nameinfo" +#define DPNA_KEY_NAT_RESOLVER_A "natresolver" +#define DPNA_KEY_NAT_RESOLVER_USER_STRING_A "natresolveruserstring" #define DPNA_KEY_PARITY_A "parity" #define DPNA_KEY_PHONENUMBER_A "phonenumber" #define DPNA_KEY_PORT_A "port" @@ -94,6 +96,8 @@ typedef struct sockaddr SOCKADDR; # define DPNA_KEY_FLOWCONTROL (const WCHAR []){ 'f','l','o','w','c','o','n','t','r','o','l',0 } # define DPNA_KEY_HOSTNAME (const WCHAR []){ 'h','o','s','t','n','a','m','e',0 } # define DPNA_KEY_NAMEINFO (const WCHAR []){ 'n','a','m','e','i','n','f','o',0 } +# define DPNA_KEY_NAT_RESOLVER (const WCHAR []){'n', 'a', 't', 'r', 'e', 's', 'o', 'l', 'v', 'e', 'r', 0} +# define DPNA_KEY_NAT_RESOLVER_USER_STRING (const WCHAR []){'n', 'a', 't', 'r', 'e', 's', 'o', 'l', 'v', 'e', 'r', 'u', 's', 'e', 'r', 's', 't', 'r', 'i', 'n', 'g', 0} # define DPNA_KEY_PARITY (const WCHAR []){ 'p','a','r','i','t','y',0 } # define DPNA_KEY_PHONENUMBER (const WCHAR []){ 'p','h','o','n','e','n','u','m','b','e','r',0 } # define DPNA_KEY_PORT (const WCHAR []){ 'p','o','r','t',0 } @@ -130,6 +134,8 @@ typedef struct sockaddr SOCKADDR; # define DPNA_KEY_FLOWCONTROL L"flowcontrol" # define DPNA_KEY_HOSTNAME L"hostname" # define DPNA_KEY_NAMEINFO_A L"nameinfo" +# define DPNA_KEY_NAT_RESOLVER L"natresolver" +# define DPNA_KEY_NAT_RESOLVER_USER_STRING L"natresolveruserstring" # define DPNA_KEY_PARITY L"parity" # define DPNA_KEY_PHONENUMBER L"phonenumber" # define DPNA_KEY_PORT L"port" @@ -166,6 +172,8 @@ static const WCHAR DPNA_KEY_DEVICE[] = { 'd','e','v','i','c','e',0 }; static const WCHAR DPNA_KEY_FLOWCONTROL[] = { 'f','l','o','w','c','o','n','t','r','o','l',0 }; static const WCHAR DPNA_KEY_HOSTNAME[] = { 'h','o','s','t','n','a','m','e',0 }; static const WCHAR DPNA_KEY_NAMEINFO[] = { 'n','a','m','e','i','n','f','o',0 }; +static const WCHAR DPNA_KEY_NAT_RESOLVER[] = {'n', 'a', 't', 'r', 'e', 's', 'o', 'l', 'v', 'e', 'r', 0}; +static const WCHAR DPNA_KEY_NAT_RESOLVER_USER_STRING[] = {'n', 'a', 't', 'r', 'e', 's', 'o', 'l', 'v', 'e', 'r', 'u', 's', 'e', 'r', 's', 't', 'r', 'i', 'n', 'g', 0}; static const WCHAR DPNA_KEY_PARITY[] = { 'p','a','r','i','t','y',0 }; static const WCHAR DPNA_KEY_PHONENUMBER[] = { 'p','h','o','n','e','n','u','m','b','e','r',0 }; static const WCHAR DPNA_KEY_PORT[] = { 'p','o','r','t',0 };