/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS WinSock 2 DLL
* FILE: misc/ns.c
* PURPOSE: Namespace APIs
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
* REVISIONS:
* CSH 01/09-2000 Created
*/
#include "ws2_32.h"
#ifndef BUFSIZ
#define BUFSIZ 1024
#endif/*BUFSIZ*/
#ifndef MAX_HOSTNAME_LEN
#define MAX_HOSTNAME_LEN 256
#endif
/* Name resolution APIs */
/*
* @unimplemented
*/
INT
EXPORT
WSAAddressToStringA(IN LPSOCKADDR lpsaAddress,
IN DWORD dwAddressLength,
IN LPWSAPROTOCOL_INFOA lpProtocolInfo,
OUT LPSTR lpszAddressString,
IN OUT LPDWORD lpdwAddressStringLength)
{
DWORD size;
CHAR buffer[54]; /* 32 digits + 7':' + '[' + '%" + 5 digits + ']:' + 5 digits + '\0' */
CHAR *p;
if (!lpsaAddress) return SOCKET_ERROR;
if (!lpszAddressString || !lpdwAddressStringLength) return SOCKET_ERROR;
switch(lpsaAddress->sa_family)
{
case AF_INET:
if (dwAddressLength < sizeof(SOCKADDR_IN)) return SOCKET_ERROR;
sprintf( buffer, "%u.%u.%u.%u:%u",
(unsigned int)(ntohl( ((SOCKADDR_IN *)lpsaAddress)->sin_addr.s_addr ) >> 24 & 0xff),
(unsigned int)(ntohl( ((SOCKADDR_IN *)lpsaAddress)->sin_addr.s_addr ) >> 16 & 0xff),
(unsigned int)(ntohl( ((SOCKADDR_IN *)lpsaAddress)->sin_addr.s_addr ) >> 8 & 0xff),
(unsigned int)(ntohl( ((SOCKADDR_IN *)lpsaAddress)->sin_addr.s_addr ) & 0xff),
ntohs( ((SOCKADDR_IN *)lpsaAddress)->sin_port ) );
p = strchr( buffer, ':' );
if (!((SOCKADDR_IN *)lpsaAddress)->sin_port) *p = 0;
break;
default:
WSASetLastError(WSAEINVAL);
return SOCKET_ERROR;
}
size = strlen( buffer ) + 1;
if (*lpdwAddressStringLength < size)
{
*lpdwAddressStringLength = size;
WSASetLastError(WSAEFAULT);
return SOCKET_ERROR;
}
*lpdwAddressStringLength = size;
strcpy( lpszAddressString, buffer );
return 0;
}
/*
* @unimplemented
*/
INT
EXPORT
WSAAddressToStringW(IN LPSOCKADDR lpsaAddress,
IN DWORD dwAddressLength,
IN LPWSAPROTOCOL_INFOW lpProtocolInfo,
OUT LPWSTR lpszAddressString,
IN OUT LPDWORD lpdwAddressStringLength)
{
INT ret;
DWORD size;
WCHAR buffer[54]; /* 32 digits + 7':' + '[' + '%" + 5 digits + ']:' + 5 digits + '\0' */
CHAR bufAddr[54];
size = *lpdwAddressStringLength;
ret = WSAAddressToStringA(lpsaAddress, dwAddressLength, NULL, bufAddr, &size);
if (ret) return ret;
MultiByteToWideChar( CP_ACP, 0, bufAddr, size, buffer, sizeof( buffer )/sizeof(WCHAR));
if (*lpdwAddressStringLength < size)
{
*lpdwAddressStringLength = size;
WSASetLastError(WSAEFAULT);
return SOCKET_ERROR;
}
*lpdwAddressStringLength = size;
lstrcpyW( lpszAddressString, buffer );
return 0;
}
/*
* @unimplemented
*/
INT
EXPORT
WSAEnumNameSpaceProvidersA(IN OUT LPDWORD lpdwBufferLength,
OUT LPWSANAMESPACE_INFOA lpnspBuffer)
{
UNIMPLEMENTED
WSASetLastError(WSASYSCALLFAILURE);
return SOCKET_ERROR;
}
/*
* @unimplemented
*/
INT
EXPORT
WSAEnumNameSpaceProvidersW(IN OUT LPDWORD lpdwBufferLength,
OUT LPWSANAMESPACE_INFOW lpnspBuffer)
{
UNIMPLEMENTED
WSASetLastError(WSASYSCALLFAILURE);
return SOCKET_ERROR;
}
/*
* @unimplemented
*/
INT
EXPORT
WSAGetServiceClassInfoA(IN LPGUID lpProviderId,
IN LPGUID lpServiceClassId,
IN OUT LPDWORD lpdwBufferLength,
OUT LPWSASERVICECLASSINFOA lpServiceClassInfo)
{
UNIMPLEMENTED
WSASetLastError(WSASYSCALLFAILURE);
return SOCKET_ERROR;
}
/*
* @unimplemented
*/
INT
EXPORT
WSAGetServiceClassInfoW(IN LPGUID lpProviderId,
IN LPGUID lpServiceClassId,
IN OUT LPDWORD lpdwBufferLength,
OUT LPWSASERVICECLASSINFOW lpServiceClassInfo)
{
UNIMPLEMENTED
WSASetLastError(WSASYSCALLFAILURE);
return SOCKET_ERROR;
}
/*
* @unimplemented
*/
INT
EXPORT
WSAGetServiceClassNameByClassIdA(IN LPGUID lpServiceClassId,
OUT LPSTR lpszServiceClassName,
IN OUT LPDWORD lpdwBufferLength)
{
UNIMPLEMENTED
WSASetLastError(WSASYSCALLFAILURE);
return SOCKET_ERROR;
}
/*
* @unimplemented
*/
INT
EXPORT
WSAGetServiceClassNameByClassIdW(IN LPGUID lpServiceClassId,
OUT LPWSTR lpszServiceClassName,
IN OUT LPDWORD lpdwBufferLength)
{
UNIMPLEMENTED
WSASetLastError(WSASYSCALLFAILURE);
return SOCKET_ERROR;
}
/*
* @unimplemented
*/
INT
EXPORT
WSAInstallServiceClassA(IN LPWSASERVICECLASSINFOA lpServiceClassInfo)
{
UNIMPLEMENTED
WSASetLastError(WSASYSCALLFAILURE);
return SOCKET_ERROR;
}
/*
* @unimplemented
*/
INT
EXPORT
WSAInstallServiceClassW(IN LPWSASERVICECLASSINFOW lpServiceClassInfo)
{
UNIMPLEMENTED
WSASetLastError(WSASYSCALLFAILURE);
return SOCKET_ERROR;
}
/*
* @unimplemented
*/
INT
EXPORT
WSALookupServiceBeginA(IN LPWSAQUERYSETA lpqsRestrictions,
IN DWORD dwControlFlags,
OUT LPHANDLE lphLookup)
{
UNIMPLEMENTED
WSASetLastError(WSASYSCALLFAILURE);
return SOCKET_ERROR;
}
/*
* @unimplemented
*/
INT
EXPORT
WSALookupServiceBeginW(IN LPWSAQUERYSETW lpqsRestrictions,
IN DWORD dwControlFlags,
OUT LPHANDLE lphLookup)
{
UNIMPLEMENTED
WSASetLastError(WSASYSCALLFAILURE);
return SOCKET_ERROR;
}
/*
* @unimplemented
*/
INT
EXPORT
WSALookupServiceEnd(IN HANDLE hLookup)
{
UNIMPLEMENTED
WSASetLastError(WSASYSCALLFAILURE);
return SOCKET_ERROR;
}
/*
* @unimplemented
*/
INT
EXPORT
WSALookupServiceNextA(IN HANDLE hLookup,
IN DWORD dwControlFlags,
IN OUT LPDWORD lpdwBufferLength,
OUT LPWSAQUERYSETA lpqsResults)
{
UNIMPLEMENTED
WSASetLastError(WSASYSCALLFAILURE);
return SOCKET_ERROR;
}
/*
* @unimplemented
*/
INT
EXPORT
WSALookupServiceNextW(IN HANDLE hLookup,
IN DWORD dwControlFlags,
IN OUT LPDWORD lpdwBufferLength,
OUT LPWSAQUERYSETW lpqsResults)
{
UNIMPLEMENTED
WSASetLastError(WSASYSCALLFAILURE);
return SOCKET_ERROR;
}
/*
* @unimplemented
*/
INT
EXPORT
WSARemoveServiceClass(IN LPGUID lpServiceClassId)
{
UNIMPLEMENTED
WSASetLastError(WSASYSCALLFAILURE);
return SOCKET_ERROR;
}
/*
* @unimplemented
*/
INT
EXPORT
WSASetServiceA(IN LPWSAQUERYSETA lpqsRegInfo,
IN WSAESETSERVICEOP essOperation,
IN DWORD dwControlFlags)
{
UNIMPLEMENTED
WSASetLastError(WSASYSCALLFAILURE);
return SOCKET_ERROR;
}
/*
* @unimplemented
*/
INT
EXPORT
WSASetServiceW(IN LPWSAQUERYSETW lpqsRegInfo,
IN WSAESETSERVICEOP essOperation,
IN DWORD dwControlFlags)
{
UNIMPLEMENTED
WSASetLastError(WSASYSCALLFAILURE);
return SOCKET_ERROR;
}
/*
* @unimplemented
*/
INT
EXPORT
WSAStringToAddressA(IN LPSTR AddressString,
IN INT AddressFamily,
IN LPWSAPROTOCOL_INFOA lpProtocolInfo,
OUT LPSOCKADDR lpAddress,
IN OUT LPINT lpAddressLength)
{
INT ret, len;
LPWSTR szTemp;
WSAPROTOCOL_INFOW ProtoInfoW;
len = MultiByteToWideChar(CP_ACP,
0,
AddressString,
-1,
NULL,
0);
szTemp = HeapAlloc(GetProcessHeap(),
0,
len * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP,
0,
AddressString,
-1,
szTemp,
len);
if (lpProtocolInfo)
{
memcpy(&ProtoInfoW,
lpProtocolInfo,
FIELD_OFFSET(WSAPROTOCOL_INFOA, szProtocol));
MultiByteToWideChar(CP_ACP,
0,
lpProtocolInfo->szProtocol,
-1,
ProtoInfoW.szProtocol,
WSAPROTOCOL_LEN + 1);
}
ret = WSAStringToAddressW(szTemp,
AddressFamily,
&ProtoInfoW,
lpAddress,
lpAddressLength);
HeapFree(GetProcessHeap(),
0,
szTemp );
WSASetLastError(ret);
return ret;
}
/*
* @implemented
*/
INT
EXPORT
WSAStringToAddressW(IN LPWSTR AddressString,
IN INT AddressFamily,
IN LPWSAPROTOCOL_INFOW lpProtocolInfo,
OUT LPSOCKADDR lpAddress,
IN OUT LPINT lpAddressLength)
{
int pos=0;
int res=0;
LONG inetaddr = 0;
LPWSTR *bp=NULL;
SOCKADDR_IN *sockaddr;
if (!lpAddressLength || !lpAddress || !AddressString)
{
WSASetLastError(WSAEINVAL);
return SOCKET_ERROR;
}
sockaddr = (SOCKADDR_IN *) lpAddress;
/* Set right adress family */
if (lpProtocolInfo!=NULL)
sockaddr->sin_family = lpProtocolInfo->iAddressFamily;
else
sockaddr->sin_family = AddressFamily;
/* Report size */
if (AddressFamily == AF_INET)
{
if (*lpAddressLength < (INT)sizeof(SOCKADDR_IN))
{
*lpAddressLength = sizeof(SOCKADDR_IN);
res = WSAEFAULT;
}
else
{
// translate ip string to ip
/* rest sockaddr.sin_addr.s_addr
for we need to be sure it is zero when we come to while */
memset(lpAddress,0,sizeof(SOCKADDR_IN));
/* Set right adress family */
sockaddr->sin_family = AF_INET;
/* Get port number */
pos = wcscspn(AddressString,L":") + 1;
if (pos < (int)wcslen(AddressString))
sockaddr->sin_port = wcstol(&AddressString[pos],
bp,
10);
else
sockaddr->sin_port = 0;
/* Get ip number */
pos=0;
inetaddr=0;
while (pos < (int)wcslen(AddressString))
{
inetaddr = (inetaddr<<8) + ((UCHAR)wcstol(&AddressString[pos],
bp,
10));
pos += wcscspn( &AddressString[pos],L".") +1 ;
}
res = 0;
sockaddr->sin_addr.s_addr = inetaddr;
}
}
WSASetLastError(res);
if (!res) return 0;
return SOCKET_ERROR;
}
void check_hostent(struct hostent **he)
{
struct hostent *new_he;
WS_DbgPrint(MID_TRACE,("*he: %x\n",*he));
if(!*he)
{
new_he = HeapAlloc(GlobalHeap,
0,
sizeof(struct hostent) + MAX_HOSTNAME_LEN + 1);
new_he->h_name = (PCHAR)(new_he + 1);
new_he->h_aliases = NULL;
new_he->h_addrtype = 0; // AF_INET
new_he->h_length = 0; // sizeof(in_addr)
new_he->h_addr_list = HeapAlloc(GlobalHeap,
HEAP_ZERO_MEMORY,
sizeof(char *) * 2);
*he = new_he;
}
}
void populate_hostent(struct hostent *he, char* name, IP4_ADDRESS addr)
{
ASSERT(he);
//he = HeapAlloc(GlobalHeap, 0, sizeof(struct hostent));
//he->h_name = HeapAlloc(GlobalHeap, 0, MAX_HOSTNAME_LEN+1);
strncpy(he->h_name,
name,
MAX_HOSTNAME_LEN);
if( !he->h_aliases ) {
he->h_aliases = HeapAlloc(GlobalHeap, 0, sizeof(char *));
he->h_aliases[0] = NULL;
}
he->h_addrtype = AF_INET;
he->h_length = sizeof(IN_ADDR); //sizeof(struct in_addr);
if( he->h_addr_list[0] )
{
HeapFree(GlobalHeap,
0,
he->h_addr_list[0]);
}
he->h_addr_list[0] = HeapAlloc(GlobalHeap,
0,
MAX_HOSTNAME_LEN + 1);
WS_DbgPrint(MID_TRACE,("he->h_addr_list[0] %x\n", he->h_addr_list[0]));
RtlCopyMemory(he->h_addr_list[0],
&addr,
sizeof(addr));
he->h_addr_list[1] = NULL;
}
void free_hostent(struct hostent *he)
{
int i;
if (he)
{
if (he->h_name)
HeapFree(GlobalHeap, 0, he->h_name);
if (he->h_aliases)
{
for (i = 0; he->h_aliases[i]; i++)
HeapFree(GlobalHeap, 0, he->h_aliases[i]);
HeapFree(GlobalHeap, 0, he->h_aliases);
}
if (he->h_addr_list)
{
for (i = 0; he->h_addr_list[i]; i++)
HeapFree(GlobalHeap, 0, he->h_addr_list[i]);
HeapFree(GlobalHeap, 0, he->h_addr_list);
}
HeapFree(GlobalHeap, 0, he);
}
}
/* WinSock 1.1 compatible name resolution APIs */
/*
* @unimplemented
*/
LPHOSTENT
EXPORT
gethostbyaddr(IN CONST CHAR FAR* addr,
IN INT len,
IN INT type)
{
UNIMPLEMENTED
return (LPHOSTENT)NULL;
}
/*
Assumes rfc 1123 - adam *
addr[1] = 0;
addr[0] = inet_addr(name);
strcpy( hostname, name );
if(addr[0] == 0xffffffff) return NULL;
he.h_addr_list = (void *)addr;
he.h_name = hostname;
he.h_aliases = NULL;
he.h_addrtype = AF_INET;
he.h_length = sizeof(addr);
return &he;
From the MSDN Platform SDK: Windows Sockets 2
"The gethostbyname function cannot resolve IP address strings passed to it.
Such a request is treated exactly as if an unknown host name were passed."
Defferring to the the documented behaviour, rather than the unix behaviour
What if the hostname is in the HOSTS file? see getservbyname
* @implemented
*/
/* DnsQuery -- lib/dnsapi/dnsapi/query.c */
/* see ws2_32.h, winsock2.h*/
/*getnetworkparameters - iphlp api */
/*
REFERENCES
servent -- w32api/include/winsock2.h
PWINSOCK_THREAD_BLOCK -- ws2_32.h
dllmain.c -- threadlocal memory allocation / deallocation
lib/dnsapi
*/
/* lib/adns/src/adns.h XXX */
/*
struct hostent {
char *h_name;
char **h_aliases;
short h_addrtype;
short h_length;
char **h_addr_list;
#define h_addr h_addr_list[0]
};
struct servent {
char *s_name;
char **s_aliases;
short s_port;
char *s_proto;
};
struct hostent defined in w32api/include/winsock2.h
*/
void free_servent(struct servent* s)
{
int i;
if (s)
{
if (s->s_name)
HeapFree(GlobalHeap, 0, s->s_name);
if (s->s_aliases)
{
for (i = 0; s->s_aliases[i]; i++)
HeapFree(GlobalHeap, 0, s->s_aliases[i]);
HeapFree(GlobalHeap, 0, s->s_aliases);
}
if (s->s_proto)
HeapFree(GlobalHeap, 0, s->s_proto);
HeapFree(GlobalHeap, 0, s);
}
}
/* This function is far from perfect but it works enough */
static
LPHOSTENT
FindEntryInHosts(IN CONST CHAR FAR* name)
{
BOOL Found = FALSE;
HANDLE HostsFile;
CHAR HostsDBData[BUFSIZ] = { 0 };
PCHAR SystemDirectory = HostsDBData;
PCHAR HostsLocation = "\\drivers\\etc\\hosts";
PCHAR AddressStr, DnsName = NULL, AddrTerm, NameSt, NextLine, ThisLine, Comment;
UINT SystemDirSize = sizeof(HostsDBData) - 1, ValidData = 0;
DWORD ReadSize;
ULONG Address;
PWINSOCK_THREAD_BLOCK p = NtCurrentTeb()->WinSockData;
/* We assume that the parameters are valid */
if (!GetSystemDirectoryA(SystemDirectory, SystemDirSize))
{
WSASetLastError(WSANO_RECOVERY);
WS_DbgPrint(MIN_TRACE, ("Could not get windows system directory.\n"));
return NULL; /* Can't get system directory */
}
strncat(SystemDirectory,
HostsLocation,
SystemDirSize );
HostsFile = CreateFileA(SystemDirectory,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
NULL);
if (HostsFile == INVALID_HANDLE_VALUE)
{
WSASetLastError(WSANO_RECOVERY);
return NULL;
}
while(!Found &&
ReadFile(HostsFile,
HostsDBData + ValidData,
sizeof(HostsDBData) - ValidData,
&ReadSize,
NULL))
{
ValidData += ReadSize;
ReadSize = 0;
NextLine = ThisLine = HostsDBData;
/* Find the beginning of the next line */
while(NextLine < HostsDBData + ValidData &&
*NextLine != '\r' && *NextLine != '\n' )
{
NextLine++;
}
/* Zero and skip, so we can treat what we have as a string */
if( NextLine > HostsDBData + ValidData )
break;
*NextLine = 0; NextLine++;
Comment = strchr( ThisLine, '#' );
if( Comment ) *Comment = 0; /* Terminate at comment start */
AddressStr = ThisLine;
/* Find the first space separating the IP address from the DNS name */
AddrTerm = strchr(ThisLine, ' ');
if (AddrTerm)
{
/* Terminate the address string */
*AddrTerm = 0;
/* Find the last space before the DNS name */
NameSt = strrchr(ThisLine, ' ');
/* If there is only one space (the one we removed above), then just use the address terminator */
if (!NameSt)
NameSt = AddrTerm;
/* Move from the space to the first character of the DNS name */
NameSt++;
DnsName = NameSt;
if (!strcmp(name, DnsName))
{
Found = TRUE;
break;
}
}
/* Get rid of everything we read so far */
while( NextLine <= HostsDBData + ValidData &&
isspace (*NextLine))
{
NextLine++;
}
if (HostsDBData + ValidData - NextLine <= 0)
break;
WS_DbgPrint(MAX_TRACE,("About to move %d chars\n",
HostsDBData + ValidData - NextLine));
memmove(HostsDBData,
NextLine,
HostsDBData + ValidData - NextLine );
ValidData -= NextLine - HostsDBData;
WS_DbgPrint(MAX_TRACE,("Valid bytes: %d\n", ValidData));
}
CloseHandle(HostsFile);
if (!Found)
{
WS_DbgPrint(MAX_TRACE,("Not found\n"));
WSASetLastError(WSANO_DATA);
return NULL;
}
if (strstr(AddressStr, ":"))
{
DbgPrint("AF_INET6 NOT SUPPORTED!\n");
WSASetLastError(WSAEINVAL);
return NULL;
}
Address = inet_addr(AddressStr);
if (Address == INADDR_NONE)
{
WSASetLastError(WSAEINVAL);
return NULL;
}
populate_hostent(p->Hostent, DnsName, Address);
return p->Hostent;
}
LPHOSTENT
EXPORT
gethostbyname(IN CONST CHAR FAR* name)
{
enum addr_type
{
GH_INVALID,
GH_IPV6,
GH_IPV4,
GH_RFC1123_DNS
};
typedef enum addr_type addr_type;
addr_type addr;
int ret = 0;
char* found = 0;
DNS_STATUS dns_status = {0};
/* include/WinDNS.h -- look up DNS_RECORD on MSDN */
PDNS_RECORD dp = 0;
PWINSOCK_THREAD_BLOCK p;
LPHOSTENT Hostent;
addr = GH_INVALID;
p = NtCurrentTeb()->WinSockData;
if( !p )
{
WSASetLastError( WSANOTINITIALISED );
return NULL;
}
check_hostent(&p->Hostent); /*XXX alloc_hostent*/
/* Hostname NULL - behave like gethostname */
if(name == NULL)
{
ret = gethostname(p->Hostent->h_name, MAX_HOSTNAME_LEN);
if(ret)
{
WSASetLastError( WSAHOST_NOT_FOUND ); //WSANO_DATA ??
return NULL;
}
return p->Hostent;
}
/* Is it an IPv6 address? */
found = strstr(name, ":");
if( found != NULL )
{
addr = GH_IPV6;
goto act;
}
/* Is it an IPv4 address? */
if (!isalpha(name[0]))
{
addr = GH_IPV4;
goto act;
}
addr = GH_RFC1123_DNS;
/* Broken out in case we want to get fancy later */
act:
switch(addr)
{
case GH_IPV6:
WSASetLastError(STATUS_NOT_IMPLEMENTED);
return NULL;
break;
case GH_INVALID:
WSASetLastError(WSAEFAULT);
return NULL;
break;
/* Note: If passed an IP address, MSDN says that gethostbyname()
treats it as an unknown host.
This is different from the unix implementation. Use inet_addr()
*/
case GH_IPV4:
case GH_RFC1123_DNS:
/* DNS_TYPE_A: include/WinDNS.h */
/* DnsQuery -- lib/dnsapi/dnsapi/query.c */
/* Look for the DNS name in the hosts file */
Hostent = FindEntryInHosts(name);
if (Hostent)
return Hostent;
dns_status = DnsQuery_A(name,
DNS_TYPE_A,
DNS_QUERY_STANDARD,
0,
/* extra dns servers */ &dp,
0);
if(dns_status == 0)
{
//ASSERT(dp->wType == DNS_TYPE_A);
//ASSERT(dp->wDataLength == sizeof(DNS_A_DATA));
PDNS_RECORD curr;
for(curr=dp;
curr != NULL && curr->wType != DNS_TYPE_A;
curr = curr->pNext )
{
WS_DbgPrint(MID_TRACE,("wType: %i\n", curr->wType));
/*empty */
}
if(curr)
{
WS_DbgPrint(MID_TRACE,("populating hostent\n"));
WS_DbgPrint(MID_TRACE,("pName is (%s)\n", curr->pName));
populate_hostent(p->Hostent,
(PCHAR)curr->pName,
curr->Data.A.IpAddress);
DnsRecordListFree(dp, DnsFreeRecordList);
return p->Hostent;
}
else
{
DnsRecordListFree(dp, DnsFreeRecordList);
}
}
WS_DbgPrint(MID_TRACE,("Called DnsQuery, but host not found. Err: %i\n",
dns_status));
WSASetLastError(WSAHOST_NOT_FOUND);
return NULL;
break;
default:
WSASetLastError(WSANO_RECOVERY);
return NULL;
break;
}
WSASetLastError(WSANO_RECOVERY);
return NULL;
}
/*
* @implemented
*/
INT
EXPORT
gethostname(OUT CHAR FAR* name,
IN INT namelen)
{
DWORD size = namelen;
int ret = GetComputerNameExA(ComputerNameDnsHostname,
name,
&size);
if(ret == 0)
{
WSASetLastError(WSAEFAULT);
return SOCKET_ERROR;
}
else
{
name[namelen-1] = '\0';
return 0;
}
}
/*
* XXX arty -- Partial implementation pending a better one. This one will
* do for normal purposes.#include
*
* Return the address of a static LPPROTOENT corresponding to the named
* protocol. These structs aren't very interesting, so I'm not too ashamed
* to have this function work on builtins for now.
*
* @unimplemented
*/
static CHAR *no_aliases = 0;
static PROTOENT protocols[] =
{
{"icmp",&no_aliases, IPPROTO_ICMP},
{"tcp", &no_aliases, IPPROTO_TCP},
{"udp", &no_aliases, IPPROTO_UDP},
{NULL, NULL, 0}
};
LPPROTOENT
EXPORT
getprotobyname(IN CONST CHAR FAR* name)
{
UINT i;
for (i = 0; protocols[i].p_name; i++)
{
if (_stricmp(protocols[i].p_name, name) == 0)
return &protocols[i];
}
return NULL;
}
/*
* @unimplemented
*/
LPPROTOENT
EXPORT
getprotobynumber(IN INT number)
{
UINT i;
for (i = 0; protocols[i].p_name; i++)
{
if (protocols[i].p_proto == number)
return &protocols[i];
}
return NULL;
}
#define SKIPWS(ptr,act) \
{while(*ptr && isspace(*ptr)) ptr++; if(!*ptr) act;}
#define SKIPANDMARKSTR(ptr,act) \
{while(*ptr && !isspace(*ptr)) ptr++; \
if(!*ptr) {act;} else { *ptr = 0; ptr++; }}
static BOOL
DecodeServEntFromString(IN PCHAR ServiceString,
OUT PCHAR *ServiceName,
OUT PCHAR *PortNumberStr,
OUT PCHAR *ProtocolStr,
IN PCHAR *Aliases,
IN DWORD MaxAlias)
{
UINT NAliases = 0;
WS_DbgPrint(MAX_TRACE, ("Parsing service ent [%s]\n", ServiceString));
SKIPWS(ServiceString, return FALSE);
*ServiceName = ServiceString;
SKIPANDMARKSTR(ServiceString, return FALSE);
SKIPWS(ServiceString, return FALSE);
*PortNumberStr = ServiceString;
SKIPANDMARKSTR(ServiceString, ;);
while( *ServiceString && NAliases < MaxAlias - 1 )
{
SKIPWS(ServiceString, break);
if( *ServiceString )
{
SKIPANDMARKSTR(ServiceString, ;);
if( strlen(ServiceString) )
{
WS_DbgPrint(MAX_TRACE, ("Alias: %s\n", ServiceString));
*Aliases++ = ServiceString;
NAliases++;
}
}
}
*Aliases = NULL;
*ProtocolStr = strchr(*PortNumberStr,'/');
if( !*ProtocolStr ) return FALSE;
**ProtocolStr = 0; (*ProtocolStr)++;
WS_DbgPrint(MAX_TRACE, ("Parsing done: %s %s %s %d\n",
*ServiceName, *ProtocolStr, *PortNumberStr,
NAliases));
return TRUE;
}
#define ADJ_PTR(p,b1,b2) p = (p - b1) + b2
/*
* @implemented
*/
LPSERVENT
EXPORT
getservbyname(IN CONST CHAR FAR* name,
IN CONST CHAR FAR* proto)
{
BOOL Found = FALSE;
HANDLE ServicesFile;
CHAR ServiceDBData[BUFSIZ] = { 0 };
PCHAR SystemDirectory = ServiceDBData; /* Reuse this stack space */
PCHAR ServicesFileLocation = "\\drivers\\etc\\services";
PCHAR ThisLine = 0, NextLine = 0, ServiceName = 0, PortNumberStr = 0,
ProtocolStr = 0, Comment = 0, EndValid;
PCHAR Aliases[WS2_INTERNAL_MAX_ALIAS] = { 0 };
UINT i,SizeNeeded = 0,
SystemDirSize = sizeof(ServiceDBData) - 1;
DWORD ReadSize = 0;
PWINSOCK_THREAD_BLOCK p = NtCurrentTeb()->WinSockData;
if( !p )
{
WSASetLastError( WSANOTINITIALISED );
return NULL;
}
if( !name )
{
WSASetLastError( WSANO_RECOVERY );
return NULL;
}
if( !GetSystemDirectoryA( SystemDirectory, SystemDirSize ) )
{
WSASetLastError( WSANO_RECOVERY );
WS_DbgPrint(MIN_TRACE, ("Could not get windows system directory.\n"));
return NULL; /* Can't get system directory */
}
strncat(SystemDirectory,
ServicesFileLocation,
SystemDirSize );
ServicesFile = CreateFileA(SystemDirectory,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
NULL );
if( ServicesFile == INVALID_HANDLE_VALUE )
{
WSASetLastError( WSANO_RECOVERY );
return NULL;
}
/* Scan the services file ...
*
* We will be share the buffer on the lines. If the line does not fit in
* the buffer, then moving it to the beginning of the buffer and read
* the remnants of line from file.
*/
/* Initial Read */
ReadFile(ServicesFile,
ServiceDBData,
sizeof( ServiceDBData ) - 1,
&ReadSize, NULL );
ThisLine = NextLine = ServiceDBData;
EndValid = ServiceDBData + ReadSize;
ServiceDBData[sizeof(ServiceDBData) - 1] = '\0';
while(ReadSize)
{
for(; *NextLine != '\r' && *NextLine != '\n'; NextLine++)
{
if(NextLine == EndValid)
{
int LineLen = NextLine - ThisLine;
if(ThisLine == ServiceDBData)
{
WS_DbgPrint(MIN_TRACE,("Line too long"));
WSASetLastError( WSANO_RECOVERY );
return NULL;
}
memmove(ServiceDBData, ThisLine, LineLen);
ReadFile(ServicesFile, ServiceDBData + LineLen,
sizeof( ServiceDBData )-1 - LineLen,
&ReadSize, NULL );
EndValid = ServiceDBData + LineLen + ReadSize;
NextLine = ServiceDBData + LineLen;
ThisLine = ServiceDBData;
if(!ReadSize) break;
}
}
*NextLine = '\0';
Comment = strchr( ThisLine, '#' );
if( Comment ) *Comment = '\0'; /* Terminate at comment start */
if(DecodeServEntFromString(ThisLine,
&ServiceName,
&PortNumberStr,
&ProtocolStr,
Aliases,
WS2_INTERNAL_MAX_ALIAS) &&
!strcmp( ServiceName, name ) &&
(proto ? !strcmp( ProtocolStr, proto ) : TRUE) )
{
WS_DbgPrint(MAX_TRACE,("Found the service entry.\n"));
Found = TRUE;
SizeNeeded = sizeof(WINSOCK_GETSERVBYNAME_CACHE) +
(NextLine - ThisLine);
break;
}
NextLine++;
ThisLine = NextLine;
}
/* This we'll do no matter what */
CloseHandle( ServicesFile );
if( !Found )
{
WS_DbgPrint(MAX_TRACE,("Not found\n"));
WSASetLastError( WSANO_DATA );
return NULL;
}
if( !p->Getservbyname || p->Getservbyname->Size < SizeNeeded )
{
/* Free previous getservbyname buffer, allocate bigger */
if( p->Getservbyname )
HeapFree(GlobalHeap, 0, p->Getservbyname);
p->Getservbyname = HeapAlloc(GlobalHeap, 0, SizeNeeded);
if( !p->Getservbyname )
{
WS_DbgPrint(MIN_TRACE,("Couldn't allocate %d bytes\n",
SizeNeeded));
WSASetLastError( WSATRY_AGAIN );
return NULL;
}
p->Getservbyname->Size = SizeNeeded;
}
/* Copy the data */
memmove(p->Getservbyname->Data,
ThisLine,
NextLine - ThisLine );
ADJ_PTR(ServiceName,ThisLine,p->Getservbyname->Data);
ADJ_PTR(ProtocolStr,ThisLine,p->Getservbyname->Data);
WS_DbgPrint(MAX_TRACE, ("ServiceName: %s, Protocol: %s\n",
ServiceName,
ProtocolStr));
for( i = 0; Aliases[i]; i++ )
{
ADJ_PTR(Aliases[i],ThisLine,p->Getservbyname->Data);
WS_DbgPrint(MAX_TRACE,("Aliase %d: %s\n", i, Aliases[i]));
}
memcpy(p->Getservbyname->Aliases,
Aliases,
sizeof(Aliases));
/* Create the struct proper */
p->Getservbyname->ServerEntry.s_name = ServiceName;
p->Getservbyname->ServerEntry.s_aliases = p->Getservbyname->Aliases;
p->Getservbyname->ServerEntry.s_port = htons(atoi(PortNumberStr));
p->Getservbyname->ServerEntry.s_proto = ProtocolStr;
return &p->Getservbyname->ServerEntry;
}
/*
* @implemented
*/
LPSERVENT
EXPORT
getservbyport(IN INT port,
IN CONST CHAR FAR* proto)
{
BOOL Found = FALSE;
HANDLE ServicesFile;
CHAR ServiceDBData[BUFSIZ] = { 0 };
PCHAR SystemDirectory = ServiceDBData; /* Reuse this stack space */
PCHAR ServicesFileLocation = "\\drivers\\etc\\services";
PCHAR ThisLine = 0, NextLine = 0, ServiceName = 0, PortNumberStr = 0,
ProtocolStr = 0, Comment = 0;
PCHAR Aliases[WS2_INTERNAL_MAX_ALIAS] = { 0 };
UINT i,SizeNeeded = 0,
SystemDirSize = sizeof(ServiceDBData) - 1;
DWORD ReadSize = 0, ValidData = 0;
PWINSOCK_THREAD_BLOCK p = NtCurrentTeb()->WinSockData;
if( !p )
{
WSASetLastError( WSANOTINITIALISED );
return NULL;
}
if ( !port )
{
WSASetLastError( WSANO_RECOVERY );
return NULL;
}
if( !GetSystemDirectoryA( SystemDirectory, SystemDirSize ) )
{
WSASetLastError( WSANO_RECOVERY );
WS_DbgPrint(MIN_TRACE, ("Could not get windows system directory.\n"));
return NULL; /* Can't get system directory */
}
strncat(SystemDirectory,
ServicesFileLocation,
SystemDirSize );
ServicesFile = CreateFileA(SystemDirectory,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
NULL );
if( ServicesFile == INVALID_HANDLE_VALUE )
{
WSASetLastError( WSANO_RECOVERY );
return NULL;
}
/* Scan the services file ...
*
* We will read up to BUFSIZ bytes per pass, until the buffer does not
* contain a full line, then we will try to read more.
*
* We fall from the loop if the buffer does not have a line terminator.
*/
/* Initial Read */
while(!Found &&
ReadFile(ServicesFile,
ServiceDBData + ValidData,
sizeof( ServiceDBData ) - ValidData,
&ReadSize, NULL ) )
{
ValidData += ReadSize;
ReadSize = 0;
NextLine = ThisLine = ServiceDBData;
/* Find the beginning of the next line */
while( NextLine < ServiceDBData + ValidData &&
*NextLine != '\r' && *NextLine != '\n' ) NextLine++;
/* Zero and skip, so we can treat what we have as a string */
if( NextLine > ServiceDBData + ValidData )
break;
*NextLine = 0; NextLine++;
Comment = strchr( ThisLine, '#' );
if( Comment ) *Comment = 0; /* Terminate at comment start */
if(DecodeServEntFromString(ThisLine,
&ServiceName,
&PortNumberStr,
&ProtocolStr,
Aliases,
WS2_INTERNAL_MAX_ALIAS ) &&
(htons(atoi( PortNumberStr )) == port ) &&
(proto ? !strcmp( ProtocolStr, proto ) : TRUE) )
{
WS_DbgPrint(MAX_TRACE,("Found the port entry.\n"));
Found = TRUE;
SizeNeeded = sizeof(WINSOCK_GETSERVBYPORT_CACHE) +
(NextLine - ThisLine);
break;
}
/* Get rid of everything we read so far */
while( NextLine <= ServiceDBData + ValidData &&
isspace( *NextLine ) )
{
NextLine++;
}
WS_DbgPrint(MAX_TRACE,("About to move %d chars\n",
ServiceDBData + ValidData - NextLine));
memmove(ServiceDBData,
NextLine,
ServiceDBData + ValidData - NextLine );
ValidData -= NextLine - ServiceDBData;
WS_DbgPrint(MAX_TRACE,("Valid bytes: %d\n", ValidData));
}
/* This we'll do no matter what */
CloseHandle( ServicesFile );
if( !Found )
{
WS_DbgPrint(MAX_TRACE,("Not found\n"));
WSASetLastError( WSANO_DATA );
return NULL;
}
if( !p->Getservbyport || p->Getservbyport->Size < SizeNeeded )
{
/* Free previous getservbyport buffer, allocate bigger */
if( p->Getservbyport )
HeapFree(GlobalHeap, 0, p->Getservbyport);
p->Getservbyport = HeapAlloc(GlobalHeap,
0,
SizeNeeded);
if( !p->Getservbyport )
{
WS_DbgPrint(MIN_TRACE,("Couldn't allocate %d bytes\n",
SizeNeeded));
WSASetLastError( WSATRY_AGAIN );
return NULL;
}
p->Getservbyport->Size = SizeNeeded;
}
/* Copy the data */
memmove(p->Getservbyport->Data,
ThisLine,
NextLine - ThisLine );
ADJ_PTR(PortNumberStr,ThisLine,p->Getservbyport->Data);
ADJ_PTR(ProtocolStr,ThisLine,p->Getservbyport->Data);
WS_DbgPrint(MAX_TRACE, ("Port Number: %s, Protocol: %s\n",
PortNumberStr, ProtocolStr));
for( i = 0; Aliases[i]; i++ )
{
ADJ_PTR(Aliases[i],ThisLine,p->Getservbyport->Data);
WS_DbgPrint(MAX_TRACE,("Aliases %d: %s\n", i, Aliases[i]));
}
memcpy(p->Getservbyport->Aliases,Aliases,sizeof(Aliases));
/* Create the struct proper */
p->Getservbyport->ServerEntry.s_name = ServiceName;
p->Getservbyport->ServerEntry.s_aliases = p->Getservbyport->Aliases;
p->Getservbyport->ServerEntry.s_port = port;
p->Getservbyport->ServerEntry.s_proto = ProtocolStr;
WS_DbgPrint(MID_TRACE,("s_name: %s\n", ServiceName));
return &p->Getservbyport->ServerEntry;
}
/*
* @implemented
*/
ULONG
EXPORT
inet_addr(IN CONST CHAR FAR* cp)
/*
* FUNCTION: Converts a string containing an IPv4 address to an unsigned long
* ARGUMENTS:
* cp = Pointer to string with address to convert
* RETURNS:
* Binary representation of IPv4 address, or INADDR_NONE
*/
{
UINT i;
PCHAR p;
ULONG u = 0;
p = (PCHAR)cp;
if (!p)
{
WSASetLastError(WSAEFAULT);
return INADDR_NONE;
}
if (strlen(p) == 0)
return INADDR_NONE;
if (strcmp(p, " ") == 0)
return 0;
for (i = 0; i <= 3; i++)
{
u += (strtoul(p, &p, 0) << (i * 8));
if (strlen(p) == 0)
return u;
if (p[0] != '.')
return INADDR_NONE;
p++;
}
return u;
}
/*
* @implemented
*/
CHAR FAR*
EXPORT
inet_ntoa(IN IN_ADDR in)
{
CHAR b[10];
PCHAR p;
p = ((PWINSOCK_THREAD_BLOCK)NtCurrentTeb()->WinSockData)->Intoa;
_itoa(in.S_un.S_addr & 0xFF, b, 10);
strcpy(p, b);
_itoa((in.S_un.S_addr >> 8) & 0xFF, b, 10);
strcat(p, ".");
strcat(p, b);
_itoa((in.S_un.S_addr >> 16) & 0xFF, b, 10);
strcat(p, ".");
strcat(p, b);
_itoa((in.S_un.S_addr >> 24) & 0xFF, b, 10);
strcat(p, ".");
strcat(p, b);
return (CHAR FAR*)p;
}
/*
* @implemented
*/
VOID
EXPORT
freeaddrinfo(struct addrinfo *pAddrInfo)
{
struct addrinfo *next, *cur;
cur = pAddrInfo;
while (cur)
{
next = cur->ai_next;
if (cur->ai_addr)
HeapFree(GetProcessHeap(), 0, cur->ai_addr);
if (cur->ai_canonname)
HeapFree(GetProcessHeap(), 0, cur->ai_canonname);
HeapFree(GetProcessHeap(), 0, cur);
cur = next;
}
}
struct addrinfo *
new_addrinfo(struct addrinfo *prev)
{
struct addrinfo *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct addrinfo));
if (prev)
prev->ai_next = ret;
return ret;
}
/*
* @implemented
*/
INT
EXPORT
getaddrinfo(const char FAR * nodename,
const char FAR * servname,
const struct addrinfo FAR * hints,
struct addrinfo FAR * FAR * res)
{
struct addrinfo *ret = NULL, *ai;
ULONG addr;
USHORT port;
struct servent *se;
char *proto;
LPPROTOENT pent;
DNS_STATUS dns_status;
PDNS_RECORD dp, currdns;
struct sockaddr_in *sin;
INT error;
if (res == NULL)
{
error = WSAEINVAL;
goto End;
}
if (nodename == NULL && servname == NULL)
{
error = WSAHOST_NOT_FOUND;
goto End;
}
if (!WSAINITIALIZED)
{
error = WSANOTINITIALISED;
goto End;
}
if (servname)
{
/* converting port number */
port = strtoul(servname, NULL, 10);
/* service name was specified? */
if (port == 0)
{
/* protocol was specified? */
if (hints && hints->ai_protocol)
{
pent = getprotobynumber(hints->ai_protocol);
if (pent == NULL)
{
error = WSAEINVAL;
goto End;
}
proto = pent->p_name;
}
else
proto = NULL;
se = getservbyname(servname, proto);
if (se == NULL)
{
error = WSATYPE_NOT_FOUND;
goto End;
}
port = se->s_port;
}
else
port = htons(port);
}
else
port = 0;
if (nodename)
{
/* Is it an IPv6 address? */
if (strstr(nodename, ":"))
{
error = WSAHOST_NOT_FOUND;
goto End;
}
/* Is it an IPv4 address? */
addr = inet_addr(nodename);
if (addr != INADDR_NONE)
{
ai = new_addrinfo(NULL);
ai->ai_family = PF_INET;
ai->ai_addrlen = sizeof(struct sockaddr_in);
ai->ai_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ai->ai_addrlen);
sin = (struct sockaddr_in *)ai->ai_addr;
sin->sin_family = AF_INET;
sin->sin_port = port;
RtlCopyMemory(&sin->sin_addr, &addr, sizeof(sin->sin_addr));
if (hints)
{
if (ai->ai_socktype == 0)
ai->ai_socktype = hints->ai_socktype;
if (ai->ai_protocol == 0)
ai->ai_protocol = hints->ai_protocol;
}
ret = ai;
}
else
{
/* resolving host name */
dns_status = DnsQuery_A(nodename,
DNS_TYPE_A,
DNS_QUERY_STANDARD,
0,
/* extra dns servers */ &dp,
0);
if (dns_status == 0)
{
ai = NULL;
for (currdns = dp; currdns; currdns = currdns->pNext )
{
/* accept only A records */
if (currdns->wType != DNS_TYPE_A) continue;
ai = new_addrinfo(ai);
if (ret == NULL)
ret = ai;
ai->ai_family = PF_INET;
ai->ai_addrlen = sizeof(struct sockaddr_in);
ai->ai_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ai->ai_addrlen);
sin = (struct sockaddr_in *)ret->ai_addr;
sin->sin_family = AF_INET;
sin->sin_port = port;
RtlCopyMemory(&sin->sin_addr, &currdns->Data.A.IpAddress, sizeof(sin->sin_addr));
if (hints)
{
if (ai->ai_socktype == 0)
ai->ai_socktype = hints->ai_socktype;
if (ai->ai_protocol == 0)
ai->ai_protocol = hints->ai_protocol;
}
}
DnsRecordListFree(dp, DnsFreeRecordList);
}
}
}
else
{
ai = new_addrinfo(NULL);
ai->ai_family = PF_INET;
ai->ai_addrlen = sizeof(struct sockaddr_in);
ai->ai_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ai->ai_addrlen);
sin = (struct sockaddr_in *)ai->ai_addr;
sin->sin_family = AF_INET;
sin->sin_port = port;
if (hints)
{
if (!(hints->ai_flags & AI_PASSIVE))
{
sin->sin_addr.S_un.S_un_b.s_b1 = 127;
sin->sin_addr.S_un.S_un_b.s_b2 = 0;
sin->sin_addr.S_un.S_un_b.s_b3 = 0;
sin->sin_addr.S_un.S_un_b.s_b4 = 1;
}
if (ai->ai_socktype == 0)
ai->ai_socktype = hints->ai_socktype;
if (ai->ai_protocol == 0)
ai->ai_protocol = hints->ai_protocol;
}
ret = ai;
}
if (ret == NULL)
{
error = WSAHOST_NOT_FOUND;
goto End;
}
if (hints && hints->ai_family != PF_UNSPEC && hints->ai_family != PF_INET)
{
freeaddrinfo(ret);
error = WSAEAFNOSUPPORT;
goto End;
}
*res = ret;
error = 0;
End:
WSASetLastError(error);
return error;
}
/* EOF */