/* * 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" #include #include #include #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 */