Binding web requests to specific network adapter

484 Views Asked by At

Background

I have a mobile embedded device (Ubuntu/Mono) with 2 network adapters. One is WiFi and the other is GSM. The requirement is that when the WiFi adapter is connected to the internet (within range of a predetermined AP), the application uploads data (HTTPS POST) via WiFi but when WiFi is not available, but GSM is, it uploads data via GSM link.

Testing

In order to achieve this, I created a cloud-based webservice that returns OK if you issue a HTTP GET to it. The idea is to have a thread periodically issue the GET request bound to the particular adapter and check the result. A result of OK means that the adapter is connected to the internet while a timeout typically means it is not. I can then use this to determine which adapter to use for requests.

I created a small test app that starts a thread that issues the GET requests bound to the specific adapter. I use the request.BindIPEndPointDelegate to bind the request to the adapter. When I run the app on the WiFi adapter, the result is as expected. When the WiFi AP is on, the requests return OK, when the AP is off, the requests time out. Same when I run the app on the GSM adapter.

However, when I update the app to start 2 threads, one for WiFi adapter and GSM adapter, a problem occurs. When the AP is on, the WiFi and GSM requests go through fine. When I switch off AP, WiFi requests initially time out but after a while returns a successful result, which is wrong. Because the URI for both threads is the same, I suspect that the ServicePointManager returns the same ServicePoint to both threads and somehow because of the multi-threading this goes haywire.

The next test was to create 2 different endpoints. One each for WiFi and GSM requests, hoping that ServicePointManager would always return different ServicePoints. Unfortunately this had no positive impact.

I would appreciate suggestions.

The code is as follows:

  private HttpWebRequest CreateRequest(Uri webApiUri,IPAddress adapterAddress)
  {
   IPEndPoint endPoint = new IPEndPoint(adapterAddress, 0);

   HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(webApiUri);

   webRequest.ServicePoint.BindIPEndPointDelegate =
      delegate(ServicePoint servicePoint, IPEndPoint remoteEndPoint, int retryCount)
      {
         if (retryCount == 1)
          throw new WebException(string.Format("Cannot bind to adapter {0}", endPoint));

        return endPoint;
      };

    return webRequest;
  }
0

There are 0 best solutions below