user3681853
user3681853

Reputation: 51

Getting error 10049 (address not avai) on sendto() in UDP connection, but bind() worked

EDIT #2: The problem was I stupidly had the memset parameter order backwards, so, I wasn't zero'ing out my structure and thus must have had some garbage values in some of the rarely used fields. Which presumably explains why it initially worked on my system but not on the customer. I don't think I even got a compiler warning on it.

EDIT #1: Remy suggested I use InetNtop instead of my own little ipv6rev() function to print out the IPv6 address. I did that and got basically the same results. His next suggestion is to build a SSCCE which I will work on. But, for the moment, I am just editing this to note the use if InetNtop().

The application I am writing is sort-of a software router, where I get data on one socket (which happens to be IPv4) and send it out another on IPv6 UDP. I had it working on my machine, but, when I installed my application at customer, the sendto calls fail. I was initially communicating with another machine, but, to make the test as simple as possible, I put the UPD IPv6 receiver on the same machine, with its own IP. Using netstat, I seem to see that I've bound properly:

  UDP    [2620:175:e10:2000:10:90:177:104]:20000  *:*
 [NATerator.exe]
  UDP    [2620:175:e10:2000:10:90:177:fff0]:20000  *:*
 [node.exe]

"NATerator" being my software router application, and the receiver being a Java app (node.exe) So, they are both bound to port 20000, but to different IP addresses. So, presumably, I should be able to send from ...:104 to ...:fff0 I would think.

But the sendto() fails with 10049. Which seems to indicate that I'm sending to a bad IP address or port for the socket. So, I added debug message to print out the IP address and port and it looks like I am sending to the right address. The debug message prints out:

2014-09-08 05:17:47.155 NATERATOR 7564 [TID=0x4cdc] - omniSocketThread: socket 2264 received bytes 24. NAT ok, calling sendto() 2620:0175:0e10:2000:0010:0090:0177:fff0 port 20000 {.\NATerator.cpp:669}
2014-09-08 05:17:47.181 NATERATOR 7564 [TID=0x4cdc] - omniSocketThread: Error sending data 10049

Here is the code for the debug message before sendto, then the call to sendto and the debug after it:

char ipv6String[100];
sockaddr_in6 *ipv6_addr;
ipv6_addr = (sockaddr_in6 *) &to;
InetNtop(AF_INET6, &ipv6_addr->sin6_addr, ipv6String, sizeof(ipv6String));

cpu_debug(CPU_DEBUG_ERROR,
    "omniSocketThread: socket %d received bytes %d. NAT ok, calling sendto() IP %s port %d\n",
    *csock, bytecount, ipv6String, htons(ipv6_addr->sin6_port));

bytecount = sendto(rtusock, (char *) buffer, bytecount, 0, (const sockaddr *) &to, tolen);

if(bytecount==SOCKET_ERROR)
{
        "omniSocketThread: Error sending data %d\n", WSAGetLastError());
    continue;
}

Note that "cpu_debug" is an inhouse debug logger that operates like printf().

The code where I initially open the socket is here. I don't currently set any socket options. Not sure I need any. I just call socket() and bind() like so:

rtusock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
if (rtusock == -1)
{
    return(false);
}

in6_addr ipv6addr;
lookupHost(local_ipv6, &ipv6addr);

memset(&sinIPv6, 0, sizeof(sinIPv6));
sinIPv6.sin6_family = AF_INET6;
//  sinIPv6.sin6_addr   = in6addr_any;
memcpy(&sinIPv6.sin6_addr, &ipv6addr, sizeof(in6_addr));
sinIPv6.sin6_port   = htons(rtuport);
sockstatus = bind(rtusock, (struct sockaddr *) &sinIPv6, sizeof(sockaddr_in6));

if( sockstatus == -1 )
{
    return(false);
}

The lookupHost function gets fills in the in6_addr structure, which I think has to be working, since nestat shows the application bound. The "rtuport" is defined as 20000. I should have made the name in all caps since it is a #define constant. So, the creation of the socket() and bind() calls look like the work. But perhaps I need some socket options set?

At any rate, the last piece of relevant code is where I fill in the "to" structure. It is defined as:

struct      sockaddr_storage to;
int         tolen;

tolen = sizeof(to);

I have a function that populates to:

bool omniNATerator(struct sockaddr_storage *to, USHORT received_dest)
{
    struct sockaddr_in6 *ipv6_addr = (sockaddr_in6 *) to;

    memset(to, sizeof(sockaddr_storage), 0);
    memcpy(&ipv6_addr->sin6_addr, &rtu_to_ipv6_map[received_dest], sizeof(in6_addr) );
    ipv6_addr->sin6_family = AF_INET6;
    ipv6_addr->sin6_port = htons(rtuport);

Where rtu_to_ipv6_map is defined as follows:

in6_addr rtu_to_ipv6_map[65536];

And, I'm reasonably confident that the value in that array is the correct address because I unpack it back out in the debug message, and it correctly states the destination address.

So, perhaps I am overlooking something simple. But, as near as I can see, I have the socket open, I'm sending to an available and reasonable IP address. (I can ping both IP addresses. So it should work, but it doesn't. Any idea what I might be missing? And if it is stupid of me, maybe not downvote me too bad, LOL.

Oh, I might as well list the output from IPconfig:

Ethernet adapter IPv6:

   Connection-specific DNS Suffix  . :
   IPv6 Address. . . . . . . . . . . : 2620:175:e10:2000:10:90:177:104
   IPv6 Address. . . . . . . . . . . : 2620:175:e10:2000:10:90:177:fff0
   Link-local IPv6 Address . . . . . : fe80::cdd7:56a8:1afd:39e9%13
   Default Gateway . . . . . . . . . :

So, any ideas?

PS. I'm not a expert socket programmer. But, I have written a few socket related apps, with some previous help from this site. But, I know that there is much I don't know. Thanks for any help!

Upvotes: 1

Views: 4602

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 597215

10049 (WSAEADDRNOTAVAIL) means the specified IP address is not valid. So clearly you are doing something wrong with the to variable that you are passing to sendto(), and your debug messages are likely hiding the problem.

For instance, the use of ipv6rev() is suspicious to me. If you are tracking the IPs correctly, you should not have to reverse them since they should be in the correct format from the very beginning. For display purposes, you should be using a function like InetNtop() or RtlIpv6AddressToString() instead of formatting them manually.

That suggests that the to variable is likely in the wrong format to begin with. It looks like to gets filled in using data from rtu_to_ipv6_map[], but you did not show how you are populating that array, so it is hard to know for sure if that is where your root problem is occurring.

This is the kind of situation where you really need to provide an SSCCE so others can reproduce the problem.

Upvotes: 2

Related Questions