< Chap 8: Index | Winsock2 Main | Register and install services >


 

 

Registration and Name Resolution 8 Part 1

 

 

What do we have in this chapter 8 part 1?

  1. Background

  2. Name Space Models

  3. Enumerating Name Spaces

 

This chapter covers the protocol-independent name registration and resolution model introduced by Winsock 2. The method introduced by Winsock 1 using GetService() and SetService() is now obsolete; therefore, we will not cover it. We will first give a bit of background on the importance and uses of name registration and resolution. Then we will move into the different types of name registration models available, followed by a description of the functions that Winsock 2 provides that can be used to resolve names. We will also cover how to register your own services for others to look up, how to query DNS names and how to query for IP network names using the NLA service.

 

Background

 

Name registration is the process of associating a user-friendly name with a protocol-specific address. Host names and their IP addresses are a good example. Most people find it cumbersome to remember a workstation's address, such as “157.54.185.186.” They would rather name their machines something easier to remember, such as “MP3Server.” In the case of IP, DNS maps IP addresses to names. Other protocols offer ways of registering their specific addresses to friendlier names. Name spaces will be discussed in more detail in the next section.

Not only do you want to be able to register and resolve host names, you would also like the ability to map your Winsock server's address so that clients can retrieve it to connect to the server. For example, you might have a server running on machine 157.64.185.186 off port 5000. If the server runs on only that machine, you can always hardcode the server address in the client application.

But what if you wanted a more dynamic server, one that can run on multiple machines, perhaps a distributed application with fault tolerance? If one server crashed or was too busy, another instance could be started somewhere else to service clients. In this case, finding out where the servers are possibly running can create headaches. Ideally, you want the ability to register your server, named “Fault-Tolerant Distributed Server” with multiple addresses. In addition, you want to be able to dynamically update the registered service and its addresses. This is what name registration and resolution is all about, and this chapter will address the facilities Winsock offers to accommodate distributed server registration and name resolution.

 

Name Space Models

 

Before we begin to explore the Winsock function, we need to introduce the various name space models that most of the protocols adhere to. A name space offers the capability to associate the protocol and its addressing attributes with a user-friendly name. Some of the more common name spaces are DNS for IP and the NetWare Directory Services (NDS) from Novell for IPX. These name spaces vary widely in their organization and implementation. Some of their properties are particularly important in understanding how to register and resolve names from Winsock.

There are three different types of name spaces: dynamic, static, and persistent. A dynamic name space allows you to register a service on the fly. Also, clients can look up the service at run time. Typically, a dynamic name space relies on periodically broadcasting service information to signal that the service is continuously available. Examples of dynamic name spaces include SAP, used in an IPX networking environment and AppleTalk's NBP name space.

Static name spaces are the least flexible of the three types. Registering a service in a static name space requires that it be manually registered ahead of time. There is no way to register a name with a static name space from Winsock, there is only a method of resolving names. DNS is an example of a static name space. For example, with DNS you manually enter IP addresses and host names into a file that the DNS service uses to handle resolution requests. The Windows XP platform supports dynamic DNS, but in general, the Winsock interface does not provide a method to update DNS.

Persistent name spaces, like dynamic name spaces, allow services to register on the fly. Unlike dynamic name spaces, however, the persistent model maintains the registration information in nonvolatile storage, such as a file on a disk. Only when the service requests that it be removed will a persistent name space delete its entry. The advantage of a persistent name space is that it is flexible yet does not continually broadcast any kind of availability information. The drawback is that if a service is not well behaved (or is poorly written), it can go away without ever notifying the name space provider to remove its service entry, leading clients to believe incorrectly that the service is still available. NDS is an example of a persistent name space.

 

Enumerating Name Spaces

 

Now that you are acquainted with the various attributes of a name space, let's examine how to find out which name spaces are available on a machine. Most of the predefined name spaces are declared in the NSPAPI.H header file. Each name space has an integer value assigned to it. Table 8-1 contains some of the more commonly supported name spaces available on Windows platforms. The name spaces returned depend on which protocols are installed on the workstation. For example, unless IPX/SPX is installed on a workstation, the NS_SAP name space will not be returned.

 

Table 8-1 Supported Name Spaces

 

Name Space

Value

Description

NS_SAP

1

SAP name space; used on IPX networks

NS_NDS

2

NDS name space; used on IPX networks

NS_DNS

11

DNS name space; most commonly found on TCP/IP networks and on the Internet

ND_NTDS

32

Windows NT domain space; protocol-independent name space found on Windows 2000 and Windows XP

 

When you install IPX/SPX on a machine, the SAP name space is supported for queries only. If you want to register your own service, you also need to install the SAP Agent service. In some cases, the Client Services for NetWare are required to display local IPX interface addresses correctly. Without this service, the local addresses show up as all zeros. In addition, you must add an NDS client to use the NDS name space. You can add all of these protocols and services from the Network Control Panel.

Winsock 2 provides a method of programmatically obtaining a list of the name spaces available on a system. This is accomplished by calling the function WSAEnumNameSpaceProviders(), which is defined as:

 

INT WSAEnumNameSpaceProviders (LPDWORD lpdwBufferLength, LPWSANAMESPACE_INFO lpnspBuffer);

 

The first parameter is the size of the buffer submitted as lpnspBuffer, which is a sufficiently large array of WSANAMESPACE_INFO structures. If the function is called with an insufficiently large buffer, it fails, sets lpdwBufferLength to the required minimum size, and causes WSAGetLastError() to return WSAEFAULT. The function returns the number of WSANAMESPACE_INFO structures returned, or SOCKET_ERROR upon any error.

The WSANAMESPACE_INFO structure describes an individual name space installed on the machine. This structure is defined as:

 

typedef struct _WSANAMESPACE_INFO {

   GUID NSProviderId;

   DWORD dwNameSpace;

   BOOL fActive;

   DWORD dwVersion;

   LPTSTR lpszIdentifier;

} WSANAMESPACE_INFO, *PWSANAMESPACE_INFO, *LPWSANAMESPACE_INFO;

 

There are actually two definitions for this structure: Unicode and ANSI. The Winsock 2 header file type defines the appropriate structure to WSANAMESPACE_INFO according to how you build your project. Actually, all structures and Winsock 2 registration and name resolution functions have both ANSI and UNICODE versions. The first member of this structure, NSProviderId, is a GUID that describes this particular name space. The dwNameSpace field is the name space's integer constant, such as NS_DNS or NS_SAP. The fActive member is a Boolean value, which if true indicates that the name space is available and ready to take queries; otherwise, the provider is inactive and unable to take queries that specifically reference this provider. The dwVersion field simply identifies the version of this provider. Finally, the lpszIdentifier is a descriptive string identifier for this provider.

The following program example demonstrates the use of WSAEnumNameSpaceProviders(). Create a new empty Win32 console application project and add the project/solution name.

 

Winsock 2 - Registration and Name Resolution (RNR): example demonstrates the use of WSAEnumNameSpaceProviders(), creating new project

 

Add the following source code.

 

// Description:

//    This is a simple program that calls WSAEnumNameSpaceProviders

//    to obtain a list of the name spaces currently available on

//    the machine. This app simply lists them.

//

// No command line argument

//    WSAEnumNameSpaceProviders

//

// Link to ws2_32.lib

#include <winsock2.h>

#include <ws2tcpip.h>

#include <stdio.h>

 

#define MAX_GUID_SZ        256

 

// Function: main

// Description:

//    Load Winsock and enumerate the name spaces. First we call

//    WSAEnumNameSpaceProviders with a NULL buffer to find out

//    the required buffer size. We then allocate the buffer

//    and make the call again. Lastly, we print the structures out

int main(int argc, char **argv)

{

    WSADATA            wsd;

    char              *buff=NULL;

    WCHAR              szGuid[MAX_GUID_SZ];

    DWORD              dwSize;

    WSANAMESPACE_INFO *ns=NULL;

    int                ret, i;   

 

    // Load Winsock

    if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)

    {

        printf("WSAStartup() failed with error code %d\n", WSAGetLastError());

        return -1;

    }

    else

        printf("WSAStartup() is OK!\n");

 

    // Call the API with a NULL buffer to find out the buffer size we really need

    dwSize = 0;

    ret = WSAEnumNameSpaceProviders(&dwSize, NULL);

    if (ret != SOCKET_ERROR)

    {

        printf("Shouldn't be here!\n");

        return -1;

    }

    else

        printf("WSAEnumNameSpaceProviders() should be fine!\n");

 

    // Allocate the given size

    buff = (char *)LocalAlloc(LPTR, dwSize);

    if (!buff)

    {

        printf("Out of memory!\n");

        return -1;

    }

    else

        printf("LocalAlloc() for buffer sounds good!\n");

 

    // Make the call for real now

    ns = (WSANAMESPACE_INFO *)buff;

    ret = WSAEnumNameSpaceProviders(&dwSize, ns);

    if (ret == SOCKET_ERROR)

    {

        printf("WSAEnumNameSpaceProviders() failed with error code %d\n", WSAGetLastError());

        LocalFree(buff);

        return -1;

    }

    else

        printf("WSAEnumNameSpaceProviders() is working...\n");

 

    // Print the info out

    for(i=0; i < ret ;i++)

    {

        printf("\nName Space: %S\n", ns[i].lpszIdentifier);

        printf("        ID: ");

        switch (ns[i].dwNameSpace)

        {

            case NS_ALL:

                printf("NS_ALL\n");

                break;

            case NS_SAP:

                printf("NS_SAP\n");

                break;

            case NS_NDS:

                printf("NS_NDS\n");

                break;

            case NS_PEER_BROWSE:

                printf("NS_PEER_BROWSE\n");

                break;

            case NS_TCPIP_LOCAL:

                printf("NS_TCPIP_LOCAL\n");

                break;

            case NS_TCPIP_HOSTS:

                printf("NS_TCPIP_HOSTS\n");

                break;

            case NS_DNS:

                printf("NS_DNS\n");

                break;

            case NS_NETBT:

                printf("NS_NETBT\n");

                break;

            case NS_WINS:

                printf("NS_WINS\n");

                break;

            case NS_NBP:

                printf("NS_NBP\n");

                break;

            case NS_MS:

                printf("NS_MS\n");

                break;

            case NS_STDA:

                printf("NS_STDA\n");

                break;

            case NS_NTDS:

                printf("NS_NTDS\n");

                break;

            case NS_X500:

                printf("NS_X500\n");

                break;

            case NS_NIS:

                printf("NS_NIS\n");

                break;

            case NS_NISPLUS:

                printf("NS_NISPLUS\n");

                break;

            case NS_WRQ:

                printf("NS_WRQ\n");

                break;

            default:

                printf("%d\n", ns[i].dwNameSpace);

        }

 

        StringFromGUID2(&ns[i].NSProviderId, szGuid, MAX_GUID_SZ);

        printf("      GUID: %S\n", szGuid);

        printf("    Active: %s\n", ((ns[i].fActive) ? "YES" : "NO"));

        printf("   Version: %d\n", ns[i].dwVersion);

    }

 

    // Cleanup and exit

    if(LocalFree(buff) != NULL)

        printf("LocalFree() failed!\n");

    else

        printf("LocalFree() is OK!\n");

 

    if(WSACleanup() == 0)

        printf("WSACleanup() is OK!\n");

    else

        printf("WSACleanup() failed with error code %d\n", WSAGetLastError());

    return 0;

}

 

Build and run the project.

 

------------------------------------------------------------

Winsock 2 - Registration and Name Resolution (RNR): example demonstrates the use of WSAEnumNameSpaceProviders(), running the program showing a sample output

 

 

 


< Chap 8: Index | Winsock2 Main | Register and install services >