ServicePoint.BindIPEndPointDelegate

 

In Whidbey, it is now possible to specify the local endpoint that the HttpWebRequest should use when connecting to the other end. This can be done by setting the BindIPEndPointDelegate in the Servicepoint.

The HttpWebrequest has a Servicepoint property that returns the servicepoint associated with the request.

The delegate is called before the socket associated with the httpwebrequest attempts to connect to the remote end.

 public delegate IPEndPoint BindIPEndPoint (
         ServicePoint servicePoint, 
         IPEndPoint remoteEndPoint, 
         int retryCount)

If the bind to the endpoint specified fails, the delegate is called again. This lets you choose a different endpoint.. After Integer.MaxValue retries, OverflowException is thrown..

Now with this knowledge, identify the problem with the following piece of code.

public static IPEndPoint BindIPEndPointCallback(ServicePoint servicePoint, IPEndPoint remoteEndPoint, int retryCount)

{

Console.WriteLine("BindIPEndpoint called");

          return new IPEndPoint(IPAddress.Any,5000);

}

public static void Main()

{

HttpWebRequest request = (HttpWebRequest) WebRequest.Create("https://MyServer");

request.ServicePoint.BindIPEndPointDelegate = new BindIPEndPoint(BindIPEndPointCallback);

HttpWebResponse response = (HttpWebResponse)request.GetResponse();

}

Clue:

Consider the scenario when Myserver is ipv6 enabled and is listening on both ipv4 and ipv6 addresses on port 80.

Problem

This works perfectly fine when myserver does not support ipv6. But when myserver supports ipv6, we try to establish connection with myserver using its ipv6 address. But an ipv4 address is specified in the callback. Since the socket has already been created with AddressFamily.InterNetworkv6 when the delegate is called, the bind to an IPv4 address fails. So the delegate is called again. But the same endpoint is returned so the bind fails again. This repeats Integer.MaxValue times and then OverflowException is thrown. Note Integer.MaxValue is a really big value and it looks as though the code has gone to an infinite loop.

Solution:

Since we have the remoteEndPoint parameter in the delegate, choose the local endpoint such that the addressfamily corresponds to the remoteEndpoint. . If you are not able to choose the local Endpoint, just return null and an endpoint is automatically chosen for you.

The retryCount gives the number of times the delegate was called. The code inside the delegate can try for a specific number of times and if the bind has not succeeded till then it can return null