Thursday, March 31, 2011

winsock weirdness (c++)

I am trying to implement a function called "inet_pton" which will convert a string representation of an IPv4 or IPv6 (like "66.102.1.147" [google]) into binary network-byte ordered form. Here is the relevant part of my code:

#if defined WIN32
int inet_pton (int af, const char *src, void *dst)

{
    const void *data;
    size_t      len;
    struct      addrinfo hints, *res;

    hints.ai_family   = af;
    hints.ai_socktype = SOCK_STREAM; 
    hints.ai_protocol = IPPROTO_UDP;
    hints.ai_flags    = AI_NUMERICHOST;

    if (getaddrinfo (src, NULL, &hints, &res))
    {
        std::cout << "ERROR : inet_pton() in " << __FILE__ << " at line " << __LINE__ << std::endl;
        std::cout << "      : getaddrinfo() failed to get IP address info for \"" << src << "\"" << std::endl;
        return 0;
    }
...

So src is the incoming IP string. However, I always get an error like

getaddrinfo() failed to get IP address info for "66.102.1.147"

Can anyone with winsock experience comment? I also tried another method, the function

WSAStringToAddress ((LPTSTR)src, af, NULL, (LPSOCKADDR) &sa, &address_length)

But it always returns the error code WSAEINVAL, indicating an invalid IP string. This makes no sense to me. I'm using VS2005 as my IDE.

From stackoverflow
  • MSDN has an excellent article on using getaddrinfo:

    http://msdn.microsoft.com/en-us/library/ms738520(VS.85).aspx

    There is even an example using AI_NUMERICHOST, which sounds like what you need. They setup their "hints" struct a bit differently than you:

    ZeroMemory(&hints, sizeof(hints));
    hints.ai_flags = AI_NUMERICHOST;
    hints.ai_family = AF_UNSPEC;
    

    They don't set the other 2 properties. Maybe this will help?

  • Well, for a start you're asking for a stream socket with UDP as a protocol and that just isn't going to happen.

    Try with:

    hints.ai_family   = af;
    hints.ai_socktype = 0; 
    hints.ai_protocol = 0;
    hints.ai_flags    = AI_NUMERICHOST;
    

    and memset it to zero first as it has extra members that you're not setting...

    Also in my code I pass an empty string for the port or service when I don't have one rather than a null. The docs don't seem to specify what to do when you don't have a value; but either way an empty string works for me.

    Oh, and as always in these situations, it would be useful to know what value WSAGetLastError() returns...

    Zac : WSAGetLastError was returning WSAEINVAL. Your solution worked, I appreciate the help.
  • What's the value you're passing in for af? I have some code to do the same thing and the only differences between mine and yours are:

    • I memset the hints structure to 0
    • I always pass in PF_UNSPEC for ai_family
    • I use IPPROTO_TCP rather than IPPROTO_UDP.
  • you could also use libcurl as a reference. reinventing the wheel isn't always necessary.

0 comments:

Post a Comment