Question about Winsock2 on Windows XP vs Windows 2000

Status
This thread has been Locked and is not open to further replies. Please start a New Thread if you're having a similar issue. View our Welcome Guide to learn how to use this site.

tomdkat

Thread Starter
Retired Trusted Advisor
Joined
May 6, 2006
Messages
7,148
We recently started adding IPv6 support to an application I maintain. I'm one of many developers maintaining this application.

Anyway, we're using the getaddrinfo() function to reslove IP addresses into hostnames and so on. On a PC running Windows 2000, getaddrinfo() behaved differently than on another PC running Windows XP Pro.

Here is a test case from the getaddrinfo() MSDN page:
Code:
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>

// link with Ws2_32.lib

int __cdecl main(int argc, char **argv)
{

    //-----------------------------------------
    // Declare and initialize variables
    WSADATA wsaData;
    int iResult;

    DWORD dwRetval;

    int i = 1;
    
    char *port = "27015";

    struct addrinfo *result = NULL;
    struct addrinfo *ptr = NULL;
    struct addrinfo hints;


    // Validate the parameters
    if (argc != 2) {
        printf("usage: %s <hostname>\n", argv[0]);
        printf("  getaddrinfo provides protocol-independent translation\n");
        printf(   "   from an ANSI host name to an IP address\n");
        printf("      %s www.contoso.com\n", argv[0]);
        return 1;
    }
    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed: %d\n", iResult);
        return 1;
    }

    //--------------------------------
    // Setup the hints address info structure
    // which is passed to the getaddrinfo() function
    ZeroMemory( &hints, sizeof(hints) );
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
	hints.ai_flags = AI_NUMERICHOST |AI_PASSIVE;


//--------------------------------
// Call getaddrinfo(). If the call succeeds,
// the result variable will hold a linked list
// of addrinfo structures containing response
// information
/*    dwRetval = getaddrinfo(argv[1], port, &hints, &result);*/
[b]    dwRetval = getaddrinfo(0, port, &hints, &result);[/b]
    if ( dwRetval != 0 ) {
        printf("getaddrinfo failed with error: %d\n", dwRetval);
        WSACleanup();
        return 1;
    }

    printf("getaddrinfo returned success\n");
    
    // Retrieve each address and print out the hex bytes
    for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {

        printf("getaddrinfo response %d\n", i++);
        printf("\tFlags: 0x%x\n", ptr->ai_flags);
        printf("\tFamily: ");
        switch (ptr->ai_family) {
            case AF_UNSPEC:
                printf("Unspecified\n");
                break;
            case AF_INET:
                printf("AF_INET (IPv4)\n");
                break;
            case AF_INET6:
                printf("AF_INET6 (IPv6)\n");
                break;
            case AF_NETBIOS:
                printf("AF_NETBIOS (NetBIOS)\n");
                break;
            default:
                printf("Other %ld\n", ptr->ai_family);
                break;
        }
        printf("\tSocket type: ");
        switch (ptr->ai_socktype) {
            case 0:
                printf("Unspecified\n");
                break;
            case SOCK_STREAM:
                printf("SOCK_STREAM (stream)\n");
                break;
            case SOCK_DGRAM:
                printf("SOCK_DGRAM (datagram) \n");
                break;
            case SOCK_RAW:
                printf("SOCK_RAW (raw) \n");
                break;
            case SOCK_RDM:
                printf("SOCK_RDM (reliable message datagram)\n");
                break;
            case SOCK_SEQPACKET:
                printf("SOCK_SEQPACKET (pseudo-stream packet)\n");
                break;
            default:
                printf("Other %ld\n", ptr->ai_socktype);
                break;
        }
        printf("\tProtocol: ");
        switch (ptr->ai_protocol) {
            case 0:
                printf("Unspecified\n");
                break;
            case IPPROTO_TCP:
                printf("IPPROTO_TCP (TCP)\n");
                break;
            case IPPROTO_UDP:
                printf("IPPROTO_UDP (UDP) \n");
                break;
            default:
                printf("Other %ld\n", ptr->ai_protocol);
                break;
        }
        printf("\tLength of this sockaddr: %d\n", ptr->ai_addrlen);
        printf("\tCanonical name: %s\n", ptr->ai_canonname);
    }

    freeaddrinfo(result);
    WSACleanup();

    return 0;
}
The above runs fine on both Windows XP and Windows 2000. I've highlighted the line of code in question above in bold. Here it is again:

dwRetval = getaddrinfo(0, port, &hints, &result);

According to the MSDN documentation:
Setting the AI_PASSIVE flag indicates the caller intends to use the returned socket address structure in a call to the bind function. When the AI_PASSIVE flag is set and nodename is a NULL pointer, the IP address portion of the socket address structure is set to INADDR_ANY for IPv4 addresses and IN6ADDR_ANY_INIT for IPv6 addresses.
and
When the AI_NUMERICHOST bit is set, the nodename parameter must contain a non-NULL numeric host address string, otherwise the EAI_NONAME error is returned. This flag prevents a name resolution service from being called.
Cool.

Here is the deal: on Windows 2000 and Windows XP, if I pass a NULL to getaddrinfo:

dwRetval = getaddrinfo(0, port, &hints, &result);

The above test program runs fine and displays appropriate output.

If I pass a character zero as a C string:

dwRetval = getaddrinfo("0", port, &hints, &result);

on Windows 2000, I get a Winsock 11001 error. On Windows XP, the program continues to run as it did when I passed a null as the nodename parameter.

Why does Windows 2000 and Windows XP differ in this behavior?

Thanks!

Peace...
 
Joined
Sep 12, 2003
Messages
20,583
Hi tomdkat,

I would hazard a guess that the include files that contain the interface definitions for getaddrinfo are different between Windows 2000 and WinXP. The compiler would then compile in the difference for the respective system.

A character string of "0" would be 30 (hex) and a null would be 00 (hex). Perhaps the WinXP code interface handles both, while Windows 2000 only handles one, and thus gives an error.

-- Tom
 

tomdkat

Thread Starter
Retired Trusted Advisor
Joined
May 6, 2006
Messages
7,148
Sounds like an acceptable explanation but I still wonder which implementation is behaving correctly. getaddrinfo() is a POSIX function so I'll see how a similar test program behaves on Linux.

Thanks!

Peace...
 
Status
This thread has been Locked and is not open to further replies. Please start a New Thread if you're having a similar issue. View our Welcome Guide to learn how to use this site.

Users Who Are Viewing This Thread (Users: 0, Guests: 1)

As Seen On
As Seen On...

Welcome to Tech Support Guy!

Are you looking for the solution to your computer problem? Join our site today to ask your question. This site is completely free -- paid for by advertisers and donations.

If you're not already familiar with forums, watch our Welcome Guide to get started.

Join over 807,865 other people just like you!

Latest posts

Staff online

Members online

Top