1

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!

user3681853
  • 51
  • 2
  • 7
  • I'm not entirely sure that sending packets between two different addresses on the same computer is supported. (I do know that in some configurations a VM can't communicate with the host, which seems like it might be related.) On the other hand, it could be a bug; does it work if you change one of the port numbers? Perhaps Windows mistakenly thinks you're trying to send a packet to yourself. – Harry Johnston Sep 06 '14 at 21:32
  • Yes, you can send data from one local IP to another local IP on the same machine. WinSock handles the necessary hookup internally so it does not physically transmit the data over the network. In a VM environment, you have to use the VM's built-in router to get data passed between VM and Host. Remember, a VM acts as a separate machine, so the OS acts accordingly, that is why VMs need virtual network setups. – Remy Lebeau Sep 06 '14 at 21:59
  • @RemyLebeau: I've been trying to remember the details; I think it was that VM-host communication didn't work if the VM was set up to share the host's IP address via NAT. The VM could talk to the rest of the local network perfectly well, just not the host. But now that I think about it, the VM software may have been interfacing with the network stack below the level of WinSock, and in any case that was a problem with communication with the same IP address, not a different one. Your interpretation of the OPs problem seems much more likely. – Harry Johnston Sep 07 '14 at 20:32
  • @HarryJohnston: I usually setup Host-Only networks in my VMs when I need to exchange data between Host and VM. – Remy Lebeau Sep 07 '14 at 21:08

1 Answers1

2

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.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Hey, Remy, you are everywhere aren't you? LOL. I do a lot of Delphi, or at least used to, so, you've helped me out there many times. I will start out using your suggestion for formatting the address, and work from there. – user3681853 Sep 08 '14 at 11:46
  • Remy, I changed the code to use InetNtop() and I got the same results, same printout. I updated my question with the revision. I will next work on an SSCCE. Thanks. – user3681853 Sep 08 '14 at 12:29
  • I made a small test program, and it works. So, must be something wrong with my main program. I noticed that I swapped parameters in the memset() call, where I have the size and byte value swapped. Perhaps that is the problem, I will be testing further. Thanks for the help. – user3681853 Sep 08 '14 at 19:14
  • Hey, it looks like the problem was the stupid memset, having the parameters backwards so I had garbage in some of the fields. It seems like whenever I ask a question here, it turns out to be something very stupid on my end. Thanks much for your time. And, I will be sure to use InetNtop() in the future! – user3681853 Sep 08 '14 at 20:13