C++Builder Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
C++빌더 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
메신저 프로젝트
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C++빌더 Q&A
C++Builder Programming Q&A
[22351] WinSock2
성철경 [twinsteel] 1148 읽음    2002-10-30 18:44
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);
}
 
 


+ -

관련 글 리스트
22351 WinSock2 성철경 1148 2002/10/30
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.