WinSock 이 지원하는
gethostname
gethostbyname
gethostbyaddr
getservbyname
getservbyport
이러한 api 들을 많이 사용하실 겁니다. svcguid.h에 정의되어 있는 Network Service 를 lookup해서
결과를 받아오는 그런 루틴들인데요. 그 Network Service를 lookup하는 루틴은 .
LPBLOB getxyDataEnt(
PCHAR
pResults,
DWORD dwSize,
LPSTR
lpszName,
LPGUID lpType,
LPSTR
* lppName
);
이것으로 되어 있습니다. 이 루틴을 포팅해서
SVCID_DNS_TYPE_A 서비스를 요청했는데.. 서비스를 찾는과정(WSALookupServiceBeginA(,,,)
api사용) 에서 바로 오류가 납니다.
웃기는건 gethostbyaddr() api는 제컴에서 제대로 돌아가지 않습니다. 서비스 lookup과정에서 오류가 나지요.
제대로 포팅을 못한건지,
울트라 고수님들이 한 번 봐주십시요.
//..............................................................
void __fastcall TMainF::Test()
{
TStringList *dns_list = new
TStringList();
GetDNSServerIP(dns_list);
// get DNS servers' ip
if(dns_list->Count < 1)
{
ShowMessage("Not Found DNS
Server");
return;
}
PCHAR pResults;
pResults = new
CHAR[256];
if(!pResults)
{
SetLastError(WSA_NOT_ENOUGH_MEMORY);
return;
}
GUID guid = SVCID_DNS_TYPE_A;
LPBLOB pBlob = GetxyDataEnt(
pResults,
256,
dns_list->Strings[0].c_str(),
&guid/* ,0*/);
//..................
}
void __fastcall TMainF::GetDNSServerIP(TStringList
*list)
{
//... GetNetworkParams
FIXED_INFO * FixedInfo;
ULONG
ulOutBufLen;
DWORD
dwRetVal;
IP_ADDR_STRING * pIPAddr;
FixedInfo = (FIXED_INFO *) GlobalAlloc( GPTR, sizeof(
FIXED_INFO ) );
ulOutBufLen = sizeof( FIXED_INFO );
if( ERROR_BUFFER_OVERFLOW == GetNetworkParams(
FixedInfo, &ulOutBufLen ) )
{
GlobalFree( FixedInfo
);
FixedInfo =
(FIXED_INFO*)GlobalAlloc( GPTR, ulOutBufLen );
}
GetNetworkParams( FixedInfo, &ulOutBufLen
);
String dns_ip =
FixedInfo->DnsServerList.IpAddress.String;
list->Add(dns_ip);
pIPAddr =
FixedInfo->DnsServerList.Next;
while ( pIPAddr
)
{
list->Add(pIPAddr
->IpAddress.String);
pIPAddr =
pIPAddr->Next;
}
//.........
if(FixedInfo)
GlobalFree(
FixedInfo );
}
LPBLOB TMainF::GetxyDataEnt(PCHAR pResults, DWORD dwLength, char* lpszName,
LPGUID lpType/*,char* lppName*/)
{
AFPROTOCOLS
afp[2] = { {AF_INET,
IPPROTO_UDP},
{AF_INET, IPPROTO_TCP}};
PWSAQUERYSETA pwsaq =
(PWSAQUERYSETA)pResults;
int err;
HANDLE hRnR;
LPBLOB pvRet = 0;
INT
Err = 0;
//
// create the
query
//
memset(pwsaq, 0,
sizeof(*pwsaq));
pwsaq->dwSize =
sizeof(*pwsaq);
pwsaq->lpServiceClassId =
lpType;
pwsaq->dwNameSpace =
NS_ALL;
pwsaq->dwNumberOfProtocols =
2;
pwsaq->lpafpProtocols = &afp[0];
pwsaq->lpszServiceInstanceName = lpszName;
err =
WSALookupServiceBeginA(pwsaq,
LUP_RETURN_BLOB |
LUP_RETURN_NAME,
&hRnR);
if(err == NO_ERROR)
{
err =
WSALookupServiceNextA(
hRnR,
0,
&dwLength,
pwsaq);
if(err ==
NO_ERROR)
{
pvRet =
pwsaq->lpBlob;
}
else
{
err =
GetLastError();
}
WSALookupServiceEnd(hRnR);
if(err !=
NO_ERROR)
{
SetLastError(err);
}
}
return(pvRet);
}
//..............................................................................................
// Winsock 에서 구현한 코드
/*++
xbyrnr.cpp
Copyright (c) 1996 Microsoft
Corporation
All rights reserved
GetXbyY emulation via new WinSock2 RNR. This source
module shows
code that is built into the WinSock2 DLL
(ws2_32.dll). It
demonstrates how the older GetXByY
functions are mapped to the new
WSALookupServiceBegin,
WSALookupServiceNext, WSALookupServiceEnd
functions.
This module is not guaranteed to compile. It is provided
as source
code for RNR name-space service providers to
understand what will
be coming down to their code in
response to the traditional
GetXbyY calls.
At this time,
only
gethostname
gethostbyname
gethostbyaddr
getservbyname
getservbyport
are implemented in this manner.
Warning: This code is preliminary, and may change
before Windows
Sockets 2 is released.
Warning: This is not provided as a template for either
RNR
applications or name space providers. This code is
only intended
to illustrate what happens in the WinSock2
DLL to map the GetXbyY
calls to the new RNR
APIs.
--*/
#include "svcguid.h"
//
// Forward declares
//
LPBLOB
getxyDataEnt(
PCHAR
pResults,
DWORD dwSize,
LPSTR
lpszName,
LPGUID lpType,
LPSTR
* lppName
);
VOID
FixList(PCHAR ** List, PCHAR Base);
VOID
UnpackHostEnt(struct hostent * hostent);
VOID
UnpackServEnt(struct servent * servent);
GUID HostnameGuid = SVCID_INET_HOSTADDRBYNAME;
GUID AddressGuid =
SVCID_INET_HOSTADDRBYINETSTRING;
GUID IANAGuid =
SVCID_INET_SERVICEBYNAME;
//
// Utility to turn a list of offsets into a list of addresses.
Used
// to convert structures returned as BLOBs.
//
VOID
FixList(PCHAR ** List, PCHAR Base)
{
if(*List)
{
PCHAR * Addr;
Addr = *List = (PCHAR *)(
((DWORD)*List + Base) );
while(*Addr)
{
*Addr =
(PCHAR)(((DWORD)*Addr +
Base));
Addr++;
}
}
}
//
// Routine to convert a hostent returned in a BLOB to one
with
// usable pointers. The structure is converted
in-place.
//
VOID
UnpackHostEnt(struct hostent *
hostent)
{
PCHAR pch;
pch = (PCHAR)hostent;
if(hostent->h_name)
{
hostent->h_name =
(PCHAR)((DWORD)hostent->h_name + pch);
}
FixList(&hostent->h_aliases,
pch);
FixList(&hostent->h_addr_list,
pch);
}
//
// Routine to unpack a servent returned in a BLOB to one with
//
usable pointers. The structure is converted in-place
//
VOID
UnpackServEnt(struct servent * servent)
{
PCHAR pch;
pch = (PCHAR)servent;
FixList(&servent->s_aliases,
pch);
servent->s_name =
(PCHAR)(DWORD(servent->s_name) + pch);
servent->s_proto = (PCHAR)(DWORD(servent->s_proto) + pch);
}
struct hostent FAR * WSAAPI
gethostbyaddr(
IN
const char FAR * addr,
IN int len,
IN int type
)
/*++
Routine Description:
Get host information corresponding to an address.
Arguments:
addr - A pointer to an address in network byte
order.
len - The length of the address, which must be 4 for
PF_INET
addresses.
type - The type of the address, which must be
PF_INET.
Returns:
If no error occurs, gethostbyaddr() returns a pointer to
the
hostent structure described above. Otherwise it
returns a NULL
pointer and a specific error code is stored
with SetErrorCode().
--*/
{
CHAR
qbuf[100];
struct hostent *ph;
LPBLOB pBlob;
PCHAR pResults;
int
err, ErrorCode;
PDPROCESS Process;
PDTHREAD Thread;
err =
PROLOG(&Process,
&Thread,
&ErrorCode);
if(err != NO_ERROR)
{
SetLastError(ErrorCode);
return(NULL);
}
pResults = new CHAR[RNR_BUFFER_SIZE];
if(!pResults)
{
SetLastError(WSA_NOT_ENOUGH_MEMORY);
return(NULL);
}
//
// NOTICE. Only handles current
inet address forms.
//
(void)wsprintfA(qbuf,
"%u.%u.%u.%u",
((unsigned)addr[0] &
0xff),
((unsigned)addr[1] &
0xff),
((unsigned)addr[2] &
0xff),
((unsigned)addr[3] & 0xff));
/*
getxyDataEnt(
PCHAR pResults,
DWORD dwLength,
LPSTR lpszName,
LPGUID lpType,
LPSTR
* lppName)
*/
pBlob =
getxyDataEnt(pResults,
RNR_BUFFER_SIZE,
qbuf,
&AddressGuid,
0);
if(pBlob)
{
ph = (struct hostent
*)Thread->CopyHostEnt(pBlob);
if(ph)
{
UnpackHostEnt(ph);
}
}
else
{
ph =
0;
if(GetLastError() ==
WSASERVICE_NOT_FOUND)
{
SetLastError(WSANO_ADDRESS);
}
}
delete
pResults;
return(ph);
} // gethostbyaddr
struct hostent FAR * WSAAPI
gethostbyname(
IN
const char FAR * name
)
/*++
Routine
Description:
Get host information corresponding to a hostname.
Arguments:
name - A pointer to the null terminated name of the
host.
Returns:
If no error occurs, gethostbyname() returns a pointer to
the
hostent structure described above. Otherwise it
returns a NULL
pointer and a specific errorr code is
stored with SetErrorCode().
--*/
{
struct hostent *
hent;
LPBLOB pBlob;
PCHAR
pResults;
int err, ErrorCode;
PDPROCESS Process;
PDTHREAD Thread;
CHAR szLocalName[200]; // for storing the local name.
This
// is simply a big number
assumed
// to be large enough. This is
used
// only when the caller chooses not
to
// provide a name.
PCHAR pszName;
err =
PROLOG(&Process,
&Thread,
&ErrorCode);
if(err != NO_ERROR)
{
SetLastError(ErrorCode);
return(NULL);
}
//
// A NULL input name means look
for the local name. So,
// get it.
//
if(!name || !*name)
{
if(gethostname(szLocalName, 200)
!= NO_ERROR)
{
return(NULL);
}
pszName =
szLocalName;
}
else
{
pszName = (PCHAR)name;
}
pResults = new CHAR[RNR_BUFFER_SIZE];
if(!pResults)
{
SetLastError(WSA_NOT_ENOUGH_MEMORY);
return(NULL);
}
pBlob = getxyDataEnt(
pResults,
RNR_BUFFER_SIZE,
pszName,
&HostnameGuid,
0);
if(pBlob)
{
hent = (struct hostent
*)Thread->CopyHostEnt(pBlob);
if(hent)
{
UnpackHostEnt(hent);
}
}
else
{
hent =
0;
if(GetLastError() ==
WSASERVICE_NOT_FOUND)
{
SetLastError(WSAHOST_NOT_FOUND);
}
}
delete
pResults;
return(hent);
} // gethostbyname
int WSAAPI
gethostname(
OUT char FAR *
name,
IN int namelen
)
/*++
Routine Description:
Return the standard host name for the local
machine.
Arguments:
name - A pointer to a buffer that will
receive the host name.
namelen - The length of the buffer.
Returns:
Zero on success else SOCKET_ERROR. The error code is
stored with
SetErrorCode().
--*/
{
PCHAR
lpName;
int err, ErrorCode;
PDPROCESS Process;
PDTHREAD Thread;
PCHAR pResults;
err =
PROLOG(&Process,
&Thread,
&ErrorCode);
if(err != NO_ERROR)
{
SetLastError(ErrorCode);
return(SOCKET_ERROR);
}
pResults = new CHAR[RNR_BUFFER_SIZE];
if(!pResults)
{
SetLastError(WSA_NOT_ENOUGH_MEMORY);
return(SOCKET_ERROR);
}
if(getxyDataEnt(pResults,
RNR_BUFFER_SIZE,
NULL,
&HostnameGuid,
&lpName
))
{
INT
iSize = strlen(lpName) + 1;
if(iSize <=
namelen)
{
memcpy(name, lpName, iSize);
}
else
{
SetLastError(WSAEFAULT);
err = SOCKET_ERROR;
}
}
else
{
err = SOCKET_ERROR;
// assume LastError has been set
}
delete pResults;
return(err);
} //
gethostname
struct servent FAR * WSAAPI
getservbyport(
IN
int port,
IN const char FAR * proto
)
/*++
Routine Description:
Get service information corresponding to a port and
protocol.
Arguments:
port - The port for a service, in network byte
order.
proto - An optional pointer to a protocol name. If this
is NULL,
getservbyport() returns the first service entry for
which
the
port matches the s_port. Otherwise
getservbyport()
matches both the port and the proto.
Returns:
If no error occurs, getservbyport() returns a pointer to
the
servent structure described above. Otherwise it
returns a NULL
pointer and a specific error code is stored
with SetErrorCode().
--*/
{
PCHAR
pszTemp;
struct servent * sent;
int
err, ErrorCode;
PDPROCESS Process;
PDTHREAD Thread;
LPBLOB pBlob;
PCHAR
pResults;
err =
PROLOG(&Process,
&Thread,
&ErrorCode);
if(err != NO_ERROR)
{
SetLastError(ErrorCode);
return(NULL);
}
pResults = new CHAR[RNR_BUFFER_SIZE];
if(!pResults)
{
SetLastError(WSA_NOT_ENOUGH_MEMORY);
return(NULL);
}
if(!proto)
{
proto =
"";
}
//
// the 5 is the max number of
digits in a port
//
pszTemp = new
CHAR[strlen(proto) + 1 + 1 + 5];
wsprintfA(pszTemp,
"%d/%s", (port & 0xffff), proto);
pBlob =
getxyDataEnt(pResults,
RNR_BUFFER_SIZE,
pszTemp,
&IANAGuid,
0
);
delete pszTemp;
if(!pBlob)
{
sent = 0;
if(GetLastError() ==
WSATYPE_NOT_FOUND)
{
SetLastError(WSANO_DATA);
}
}
else
{
sent = (struct servent
*)Thread->CopyServEnt(pBlob);
if(sent)
{
UnpackServEnt(sent);
}
}
delete
pResults;
return(sent);
} // getservbyport
struct servent FAR * WSAAPI
getservbyname(
IN
const char FAR * name,
IN const char FAR *
proto
)
/*++
Routine Description:
Get service information corresponding to a service name
and
protocol.
Arguments:
name - A pointer to a null terminated
service name.
proto - An optional pointer to a null terminated
protocol name.
If
this
pointer is NULL, getservbyname() returns the
first
service entry for which the name matches the s_name or
one
of the
s_aliases. Otherwise getservbyname() matches
both
the
name and the proto.
Returns:
If no error occurs, getservbyname() returns a pointer to
the servent
structure described above. Otherwise it
returns a NULL pointer and a
specific error code is stored
with SetErrorCode().
--*/
{
PCHAR pszTemp;
struct
servent * sent;
int err, ErrorCode;
PDPROCESS Process;
PDTHREAD Thread;
LPBLOB pBlob;
PCHAR pResults;
err =
PROLOG(&Process,
&Thread,
&ErrorCode);
if(err != NO_ERROR)
{
SetLastError(ErrorCode);
return(NULL);
}
pResults = new CHAR[RNR_BUFFER_SIZE];
if(!pResults)
{
SetLastError(WSA_NOT_ENOUGH_MEMORY);
return(NULL);
}
if(!proto)
{
proto =
"";
}
pszTemp = new
CHAR[strlen(name) + strlen(proto) + 1 + 1];
wsprintfA(pszTemp, "%s/%s", name, proto);
pBlob =
getxyDataEnt(pResults,
RNR_BUFFER_SIZE,
pszTemp,
&IANAGuid,
0
);
delete pszTemp;
if(!pBlob)
{
sent = 0;
if(GetLastError() ==
WSATYPE_NOT_FOUND)
{
SetLastError(WSANO_DATA);
}
}
else
{
sent = (struct servent
*)Thread->CopyServEnt(pBlob);
if(sent)
{
UnpackServEnt(sent);
}
}
delete
pResults;
return(sent);
} // getservbyname
//
// Common routine for obtaining a xxxent buffer. Input is used
to
// execute the WSALookup series of APIs.
//
//
Args:
// pResults -- a buffer supplied by the caller to be used
in
//
the WASLookup calls. This should be as large
as
//
the caller can afford to offer.
// dwLength -- number of bytes in
pResults
// lpszName -- pointer to the service name. May by
NULL
// lpType -- pointer to the service type . This
should be one
of
//
the SVCID_INET_xxxxx types. It may be
anything
//
that produces a BLOB.
// lppName -- pointer to pointer
where the resulting name
pointer
//
is stored. May be NULL if the name is not needed.
//
//
Returns:
// 0 -- No BLOB data was returned. In
general, this means
the
// operation
failed. Evev if the WSALookupNext
succeeded
// and
returned a name, the name will not be returned.
// else -- a
pointer to the BLOB.
//
//
//
// The protocol restrictions list for
all emulation operations. This
// should limit the invoked providers to the
set that know about
// hostents and servents. If not, then the special
SVCID_INET GUIDs
// should take care of the remainder.
//
AFPROTOCOLS
afp[2] =
{
{AF_INET,
IPPROTO_UDP},
{AF_INET,
IPPROTO_TCP}
};
LPBLOB
getxyDataEnt(
PCHAR
pResults,
DWORD dwLength,
LPSTR
lpszName,
LPGUID lpType,
LPSTR
* lppName)
{
PWSAQUERYSETA pwsaq =
(PWSAQUERYSETA)pResults;
int err;
HANDLE hRnR;
LPBLOB pvRet = 0;
INT
Err = 0;
//
// create the
query
//
memset(pwsaq, 0,
sizeof(*pwsaq));
pwsaq->dwSize =
sizeof(*pwsaq);
pwsaq->lpszServiceInstanceName =
lpszName;
pwsaq->lpServiceClassId =
lpType;
pwsaq->dwNameSpace =
NS_ALL;
pwsaq->dwNumberOfProtocols =
2;
pwsaq->lpafpProtocols = &afp[0];
err =
WSALookupServiceBeginA(pwsaq,
LUP_RETURN_BLOB |
LUP_RETURN_NAME,
&hRnR);
if(err == NO_ERROR)
{
//
// The query was accepted, so
execute it via the Next call.
//
err =
WSALookupServiceNextA(
hRnR,
0,
&dwLength,
pwsaq);
//
// if NO_ERROR was returned and
a BLOB is present, this
// worked,
just return the requested information.
Otherwise,
// invent an error or
capture the transmitted one.
//
if(err ==
NO_ERROR)
{
if(pvRet
=
pwsaq->lpBlob)
{
if(lppName)
{
*lppName =
pwsaq->lpszServiceInstanceName;
}
}
else
{
err =
WSANO_DATA;
}
}
else
{
//
//
WSALookupServiceEnd clobbers LastError so
save
// it
before closing the
handle.
//
err =
GetLastError();
}
WSALookupServiceEnd(hRnR);
//
// if an error happened, stash
the value in LastError
//
if(err !=
NO_ERROR)
{
SetLastError(err);
}
}
return(pvRet);
}