none
Binding a UDP Socket

    Question

  • Hello,

    I'm trying to set up a static link between an adapter and a remote device.  I've been successful in cases where there is only one adapter, or the adapter happens to be the one selected by the OS for other various tasks.  However, in a system with many adapters, the code fails.  So, I'm trying to bind a UDP socket to a specific adapter.  Here is the code:

     

    bool SetNbUdpPort (uint32 IpAddr)
    {
    	bool Error = false;
    
    	try
    	{
    		IPHostEntry^ hostInfo = Dns::GetHostEntry("");
    		uint32 NbIpAddr = (uint32)IPAddress::HostToNetworkOrder((long)IpAddr);
    		CnbUdpSock::RemoteEndPoint = gcnew IPEndPoint(NbIpAddr, UDP_NETBURNERID_PORT);	
    		CnbUdpSock::Socket = gcnew Socket(CnbUdpSock::RemoteEndPoint->AddressFamily, SocketType::Dgram, ProtocolType::Udp);
    		CnbUdpSock::Socket->EnableBroadcast = true;
    		CnbUdpSock::Socket->Connect(CnbUdpSock::RemoteEndPoint);
    		CnbUdpSock::RxUdpClient = gcnew UdpClient(UDP_NETBURNERID_PORT);	
    		CnbUdpSock::RxUdpClient->Client->ReceiveTimeout = 500;	// The receive timeout in milliseconds. 
    		CnbUdpSock::LocalEndPoint = gcnew IPEndPoint(hostInfo->AddressList[0], UDP_NETBURNERID_PORT);
    		CnbUdpSock::Socket->Bind(CnbUdpSock::LocalEndPoint);	// Problem
    	}
    
    	catch(Exception ^ e)
    	{
    		Error = true;
    		AddToLog (" - UDP Socket Problem: " + e->ToString() + "IP: " + String::Format("{0:x8}", IpAddr));
    		AddToLog (" -- " + e->ToString());
    	}
    
    	return (Error);
    }

     Even before it gets to the bind statement, I find that the socket is already bound.  In the case above,
    I get an exception:

    System.Net.Sockets.SocketException: An invalid argument was supplied

    How should I be doing this?

    Thanks.

    Brian

    Monday, June 13, 2011 8:02 PM

Answers

  • On 6/14/2011 11:38 AM, ianut wrote:

    When I bind the socket, and then try to set up the receive client, I get an exception - something to the effect of "a port cannot be used for two purposes."

    What precisely does the process of "set[ting] up the receive client" involve?

    I suspect that the exception, and the limitation, is imposed by the wrapper you are using on top of WinSock (which I'm not familiar with), not by WinSock itself.

    P2P = peer to peer.  The target is physically connected to the NIC
    (adapter) with a crossover cable.  A static IP is used on both ends.
    There is no router or hub between the host and the target (in this
    case - a Netburner module in an embedded system).

    Do the IP addresses belong to a subnet distinct from those configured on other adapters? The OS should be able to route to the correct NIC, as long as the subnets are distinct.


    Igor Tandetnik

    • Marked as answer by ianut Wednesday, June 15, 2011 2:19 PM
    Tuesday, June 14, 2011 3:44 PM

All replies

  • ianut wrote:

    Even before it gets to the bind statement, I find that the socket is  already bound.

    Bind right after creating the socket, before connecting. When you call  Connect on an unbound socket, it gets bound automatically.


    Igor Tandetnik

    Tuesday, June 14, 2011 3:03 AM
  • Hello Igor,

    Thanks for the tip.  However, I'm still not there.  I need to set up a UDP socket that is both a sender and a receiver.  It seems when I bind the socket, it can be only one or the other.  In other words, if I bind the socket, I cannot create the receive client.  So, I thought this might work:

    bool SetNbUdpPort (uint32 IpAddr)
    {
    	bool Error = false;
    
    	try
    	{
    		uint32 NbIpAddr = (uint32)IPAddress::HostToNetworkOrder((long)IpAddr);
    		CnbUdpSock::RemoteEndPoint = gcnew IPEndPoint(NbIpAddr, UDP_NETBURNERID_PORT);	
    		CnbUdpSock::Socket = gcnew Socket(CnbUdpSock::RemoteEndPoint->AddressFamily, SocketType::Dgram, ProtocolType::Udp);
    		CnbUdpSock::Socket->EnableBroadcast = true;
    		CnbUdpSock::Socket->Connect(CnbUdpSock::RemoteEndPoint);
    
    		CnbUdpSock::RxUdpClient = gcnew UdpClient(UDP_NETBURNERID_PORT);	
    		CnbUdpSock::RxUdpClient->Client->ReceiveTimeout = 500;	// The receive timeout in milliseconds. 
    		
    		IPHostEntry^ hostInfo = Dns::GetHostEntry("");
    		CnbUdpSock::LocalEndPoint = gcnew IPEndPoint(hostInfo->AddressList[3], UDP_NETBURNERID_PORT);
    		// CnbUdpSock::LocalEndPoint = gcnew IPEndPoint(IPAddress::Any, UDP_NETBURNERID_PORT);	
    		CnbUdpSock::RandomValue = Environment::TickCount; 
    	}
    
    	catch(Exception ^ e)
    	{
    		Error = true;
    		AddToLog (" - UDP Socket Problem: " + e->ToString());
    		AddToLog (" -- " + e->ToString());
    	}
    
    	return (Error);
    }
    


    Here, instead of using IPAddress::Any on the local end point, I use a temporary static IP that I've set on the adapter (NIC) of interest.  This NIC has a P2P connection with the target.   This still fails if the NIC in use isn't the "hot one" according to the OS.  By that, I mean there seems to be some sort of pecking order.  If I use the NIC with the highest priority in the system, this all isn't necessary.  When I use a low-priority NIC, I fail to get UDP packets back from the target.  I think the OS is still expecting them at the higher-priority NIC.

    So, must I use bind in some way, and then set up a one-way connection when I send, and then delete that, and then set up another to receive, or is there some other way to set up a two-way socket, say between local IP address 192.168.0.200 and remote IP address 192.168.0.50 (mask 255.255.255.0)?

    Failing that, is there some way to temporarily disable the other NICs in the system until my process finishes?

    Thanks.

    Brian

    Tuesday, June 14, 2011 1:42 PM
  • On 6/14/2011 9:42 AM, ianut wrote:

    Thanks for the tip.  However, I'm still not there.  I need to set up
    a UDP socket that is both a sender and a receiver.  It seems when I
    bind the socket, it can be only one or the other.

    I don't see why. What's stopping it from being both?

    In other words, if
    I bind the socket, I cannot create the receive client.

    Because...?

    I suspect your problem is in calling Connect(). This is what the docs on WinSock connect() API say:

    For a connectionless socket (for example, type SOCK_DGRAM), the operation performed by connect is merely to establish a default destination address that can be used on subsequent send/ WSASend and recv/ WSARecv calls. Any datagrams received from an address other than the destination address specified will be discarded.

    Emphasis mine. So, don't use connect() unless you expect to send to, and receive from, one address/port only. Instead, use sendto() and recvfrom().

    Here, instead of using IPAddress::Any on the local end point, I use a temporary static IP that I've set on the adapter (NIC) of interest.

    I'm not sure what you mean by "use" here. Yes, I see you creating a variable named LocalEndPoint, but I don't see how it relates to any socket being used. You are still calling Connect() on an unbound socket, which implicitly binds it (to INADDR_ANY, most likely).

    This NIC has a P2P connection with the target.

    I'm not sure I understand this statement. A TCP socket may have a connection with a remote socket. NICs don't have connections. Perhaps you mean that the target is reachable from this NIC, but not from others, due to the particular network topology?

    So, must I use bind in some way, and then set up a one-way connection
    when I send, and then delete that, and then set up another to
    receive, or is there some other way to set up a two-way socket, say
    between local IP address 192.168.0.200 and remote IP address
    192.168.0.50 (mask 255.255.255.0)?

    You are using UDP sockets. UDP is a connection-less protocol. A UDP socket may send to any reachable address. It may also be bound to a particular IP address (or all IP addresses on the local machine) and a particular port, and then it may receive datagrams send to that address/port.


    Igor Tandetnik

    Tuesday, June 14, 2011 3:19 PM
  • Hello Igor,

    Thanks again for the response. 

    I did not know about sendto() and recvfrom().  I will have a look at those and see how to use them. 

    To answer some of your questions:

    When I bind the socket, and then try to set up the receive client, I get an exception - something to the effect of "a port cannot be used for two purposes." 

    P2P = peer to peer.  The target is physically connected to the NIC (adapter) with a crossover cable.  A static IP is used on both ends.  There is no router or hub between the host and the target (in this case - a Netburner module in an embedded system).

    The use of the local end point and the receive client is not shown in the quoted code.  As you can probably guess, I'm just setting some handles in a class/struct in the quoted code for later use.  However, the basic idea is that the local IP and target IP are known.  A udp packet is sent, and then a response is expected on the same port, from the target IP.

    Brian

    Tuesday, June 14, 2011 3:38 PM
  • On 6/14/2011 11:38 AM, ianut wrote:

    When I bind the socket, and then try to set up the receive client, I get an exception - something to the effect of "a port cannot be used for two purposes."

    What precisely does the process of "set[ting] up the receive client" involve?

    I suspect that the exception, and the limitation, is imposed by the wrapper you are using on top of WinSock (which I'm not familiar with), not by WinSock itself.

    P2P = peer to peer.  The target is physically connected to the NIC
    (adapter) with a crossover cable.  A static IP is used on both ends.
    There is no router or hub between the host and the target (in this
    case - a Netburner module in an embedded system).

    Do the IP addresses belong to a subnet distinct from those configured on other adapters? The OS should be able to route to the correct NIC, as long as the subnets are distinct.


    Igor Tandetnik

    • Marked as answer by ianut Wednesday, June 15, 2011 2:19 PM
    Tuesday, June 14, 2011 3:44 PM
  • Hi Igor,

    The SendTo() and RcvFrom() commands worked, after I bound the socket to the local end point.  So, that ties up the problem with UDP.  Now, I'm having the same problem in FTP.  On to a different thread!

    Thanks for your help Igor.

     

    Brian

    Wednesday, June 15, 2011 2:19 PM