wine/dlls/wsock32/protocol.c

313 lines
11 KiB
C

/*
* WSOCK32 specific functions
*
* Copyright (C) 2001 Stefan Leichter
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* All we need are a couple constants for EnumProtocols. Once it is
* moved to ws2_32 we may no longer need it
*/
#define USE_WS_PREFIX
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#include "winbase.h"
#include "winnls.h"
#include "wtypes.h"
#include "nspapi.h"
#include "winsock2.h"
#include "wsipx.h"
#include "wshisotp.h"
#include "wine/unicode.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(winsock);
/* name of the protocols
*/
static WCHAR NameIpx[] = {'I', 'P', 'X', '\0'};
static WCHAR NameSpx[] = {'S', 'P', 'X', '\0'};
static WCHAR NameSpxII[] = {'S', 'P', 'X', ' ', 'I', 'I', '\0'};
static WCHAR NameTcp[] = {'T', 'C', 'P', '/', 'I', 'P', '\0'};
static WCHAR NameUdp[] = {'U', 'D', 'P', '/', 'I', 'P', '\0'};
/*****************************************************************************
* WSOCK32_EnterSingleProtocol [internal]
*
* enters the protocol informations of one given protocol into the
* given buffer. If the given buffer is too small only the required size for
* the protocols are returned.
*
* RETURNS
* The number of protocols entered into the buffer
*
* BUGS
* - only implemented for IPX, SPX, SPXII, TCP, UDP
* - there is no check that the operating system supports the returned
* protocols
*/
static INT WSOCK32_EnterSingleProtocol( INT iProtocol,
PROTOCOL_INFOA* lpBuffer,
LPDWORD lpSize, BOOL unicode)
{ DWORD dwLength = 0, dwOldSize = *lpSize;
INT iAnz = 1;
WCHAR *lpProtName = NULL;
*lpSize = sizeof( PROTOCOL_INFOA);
switch (iProtocol) {
case WS_IPPROTO_TCP :
dwLength = (unicode) ? sizeof(WCHAR) * (strlenW(NameTcp)+1) :
WideCharToMultiByte( CP_ACP, 0, NameTcp, -1,
NULL, 0, NULL, NULL);
break;
case WS_IPPROTO_UDP :
dwLength = (unicode) ? sizeof(WCHAR) * (strlenW(NameUdp)+1) :
WideCharToMultiByte( CP_ACP, 0, NameUdp, -1,
NULL, 0, NULL, NULL);
break;
case NSPROTO_IPX :
dwLength = (unicode) ? sizeof(WCHAR) * (strlenW(NameIpx)+1) :
WideCharToMultiByte( CP_ACP, 0, NameIpx, -1,
NULL, 0, NULL, NULL);
break;
case NSPROTO_SPX :
dwLength = (unicode) ? sizeof(WCHAR) * (strlenW(NameSpx)+1) :
WideCharToMultiByte( CP_ACP, 0, NameSpx, -1,
NULL, 0, NULL, NULL);
break;
case NSPROTO_SPXII :
dwLength = (unicode) ? sizeof(WCHAR) * (strlenW(NameSpxII)+1) :
WideCharToMultiByte( CP_ACP, 0, NameSpxII, -1,
NULL, 0, NULL, NULL);
break;
default:
*lpSize = 0;
if ((iProtocol == ISOPROTO_TP4) || (iProtocol == NSPROTO_SPX))
FIXME("Protocol <%s> not implemented\n",
(iProtocol == ISOPROTO_TP4) ? "ISOPROTO_TP4" : "NSPROTO_SPX");
else
FIXME("unknown Protocol <0x%08x>\n", iProtocol);
break;
}
*lpSize += dwLength;
if ( !lpBuffer || !*lpSize || (*lpSize > dwOldSize))
return 0;
memset( lpBuffer, 0, dwOldSize);
lpBuffer->lpProtocol = (LPSTR) &lpBuffer[ iAnz];
lpBuffer->iProtocol = iProtocol;
switch (iProtocol) {
case WS_IPPROTO_TCP :
lpBuffer->dwServiceFlags = XP_FRAGMENTATION | XP_EXPEDITED_DATA |
XP_GRACEFUL_CLOSE | XP_GUARANTEED_ORDER |
XP_GUARANTEED_DELIVERY;
lpBuffer->iAddressFamily = WS_AF_INET;
lpBuffer->iMaxSockAddr = 0x10; /* NT4 SP5 */
lpBuffer->iMinSockAddr = 0x10; /* NT4 SP5 */
lpBuffer->iSocketType = SOCK_STREAM;
lpBuffer->dwMessageSize = 0;
lpProtName = NameTcp;
break;
case WS_IPPROTO_UDP :
lpBuffer->dwServiceFlags = XP_FRAGMENTATION | XP_SUPPORTS_BROADCAST |
XP_SUPPORTS_MULTICAST | XP_MESSAGE_ORIENTED |
XP_CONNECTIONLESS;
lpBuffer->iAddressFamily = WS_AF_INET;
lpBuffer->iMaxSockAddr = 0x10; /* NT4 SP5 */
lpBuffer->iMinSockAddr = 0x10; /* NT4 SP5 */
lpBuffer->iSocketType = SOCK_DGRAM;
lpBuffer->dwMessageSize = 65457; /* NT4 SP5 */
lpProtName = NameUdp;
break;
case NSPROTO_IPX :
lpBuffer->dwServiceFlags = XP_FRAGMENTATION | XP_SUPPORTS_BROADCAST |
XP_SUPPORTS_MULTICAST | XP_MESSAGE_ORIENTED |
XP_CONNECTIONLESS;
lpBuffer->iAddressFamily = WS_AF_IPX;
lpBuffer->iMaxSockAddr = 0x10; /* NT4 SP5 */
lpBuffer->iMinSockAddr = 0x0e; /* NT4 SP5 */
lpBuffer->iSocketType = SOCK_DGRAM;
lpBuffer->dwMessageSize = 576; /* NT4 SP5 */
lpProtName = NameIpx;
break;
case NSPROTO_SPX :
lpBuffer->dwServiceFlags = XP_FRAGMENTATION |
XP_PSEUDO_STREAM | XP_MESSAGE_ORIENTED |
XP_GUARANTEED_ORDER | XP_GUARANTEED_DELIVERY;
lpBuffer->iAddressFamily = WS_AF_IPX;
lpBuffer->iMaxSockAddr = 0x10; /* NT4 SP5 */
lpBuffer->iMinSockAddr = 0x0e; /* NT4 SP5 */
lpBuffer->iSocketType = 5;
lpBuffer->dwMessageSize = -1; /* NT4 SP5 */
lpProtName = NameSpx;
break;
case NSPROTO_SPXII :
lpBuffer->dwServiceFlags = XP_FRAGMENTATION | XP_GRACEFUL_CLOSE |
XP_PSEUDO_STREAM | XP_MESSAGE_ORIENTED |
XP_GUARANTEED_ORDER | XP_GUARANTEED_DELIVERY;
lpBuffer->iAddressFamily = WS_AF_IPX;
lpBuffer->iMaxSockAddr = 0x10; /* NT4 SP5 */
lpBuffer->iMinSockAddr = 0x0e; /* NT4 SP5 */
lpBuffer->iSocketType = 5;
lpBuffer->dwMessageSize = -1; /* NT4 SP5 */
lpProtName = NameSpxII;
break;
}
if (unicode)
strcpyW( (LPWSTR)lpBuffer->lpProtocol, lpProtName);
else
WideCharToMultiByte( CP_ACP, 0, lpProtName, -1, lpBuffer->lpProtocol,
dwOldSize - iAnz * sizeof( PROTOCOL_INFOA), NULL, NULL);
return iAnz;
}
/* FIXME: EnumProtocols should be moved to winsock2, and this should be
* implemented by calling out to WSAEnumProtocols. See:
* http://support.microsoft.com/support/kb/articles/Q129/3/15.asp
*/
/*****************************************************************************
* WSOCK32_EnumProtocol [internal]
*
* Enters the information about installed protocols into a given buffer
*
* RETURNS
* SOCKET_ERROR if the buffer is to small for the requested protocol infos
* on success the number of protocols inside the buffer
*
* NOTE
* NT4SP5 does not return SPX if lpiProtocols == NULL
*
* BUGS
* - NT4SP5 returns in addition these list of NETBIOS protocols
* (address family 17), each entry two times one for socket type 2 and 5
*
* iProtocol lpProtocol
* 0x80000000 \Device\NwlnkNb
* 0xfffffffa \Device\NetBT_CBENT7
* 0xfffffffb \Device\Nbf_CBENT7
* 0xfffffffc \Device\NetBT_NdisWan5
* 0xfffffffd \Device\NetBT_El9202
* 0xfffffffe \Device\Nbf_El9202
* 0xffffffff \Device\Nbf_NdisWan4
*
* - there is no check that the operating system supports the returned
* protocols
*/
static INT WSOCK32_EnumProtocol( LPINT lpiProtocols, PROTOCOL_INFOA* lpBuffer,
LPDWORD lpdwLength, BOOL unicode)
{ DWORD dwCurSize, dwOldSize = *lpdwLength, dwTemp;
INT anz = 0, i;
INT iLocal[] = { WS_IPPROTO_TCP, WS_IPPROTO_UDP, NSPROTO_IPX, NSPROTO_SPXII, 0};
if (!lpiProtocols) lpiProtocols = iLocal;
*lpdwLength = 0;
while ( *lpiProtocols )
{ dwCurSize = 0;
WSOCK32_EnterSingleProtocol( *lpiProtocols, NULL, &dwCurSize, unicode);
if ( lpBuffer && dwCurSize && ((*lpdwLength + dwCurSize) <= dwOldSize))
{ /* reserve the required space for the current protocol_info after the
* last protocol_info before the start of the string buffer and adjust
* the references into the string buffer
*/
memmove( &((char*)&lpBuffer[ anz])[dwCurSize],
&lpBuffer[ anz],
*lpdwLength - anz * sizeof( PROTOCOL_INFOA));
for (i=0; i < anz; i++)
lpBuffer[i].lpProtocol += dwCurSize;
dwTemp = dwCurSize;
anz += WSOCK32_EnterSingleProtocol( *lpiProtocols, &lpBuffer[anz],
&dwTemp, unicode);
}
*lpdwLength += dwCurSize;
lpiProtocols++;
}
if (dwOldSize < *lpdwLength) anz = SOCKET_ERROR;
return anz;
}
/*****************************************************************************
* EnumProtocolsA [WSOCK32.1111]
*
* see function WSOCK32_EnumProtocol for RETURNS, BUGS
*/
INT WINAPI EnumProtocolsA( LPINT lpiProtocols, LPVOID lpBuffer,
LPDWORD lpdwLength)
{
return WSOCK32_EnumProtocol( lpiProtocols, (PROTOCOL_INFOA*) lpBuffer,
lpdwLength, FALSE);
}
/*****************************************************************************
* EnumProtocolsW [WSOCK32.1112]
*
* see function WSOCK32_EnumProtocol for RETURNS, BUGS
*/
INT WINAPI EnumProtocolsW( LPINT lpiProtocols, LPVOID lpBuffer,
LPDWORD lpdwLength)
{
return WSOCK32_EnumProtocol( lpiProtocols, (PROTOCOL_INFOA*) lpBuffer,
lpdwLength, TRUE);
}
/*****************************************************************************
* inet_network [WSOCK32.1100]
*/
UINT WINAPI WSOCK32_inet_network(const char *cp)
{
return inet_network(cp);
}
/*****************************************************************************
* getnetbyname [WSOCK32.1101]
*/
struct netent * WINAPI WSOCK32_getnetbyname(const char *name)
{
#ifdef HAVE_GETNETBYNAME
return getnetbyname(name);
#else
return NULL;
#endif
}