From 23a894be6ff74e69990cfc78f9329a7b4559b90c Mon Sep 17 00:00:00 2001
From: Smeulf <smeulf@team-mediaportal.com>
Date: Sun, 9 Oct 2011 15:27:30 +0200
Subject: [PATCH] UPnP Library : Force HTTP Web request to a specific network interface

---
 .../CachedMultiSegmentHttpStream.cs                |    1 +
 .../UPnP/Infrastructure/CP/DeviceConnection.cs     |    2 +
 .../Infrastructure/CP/GENA/GENAClientController.cs |    6 +++
 .../UPnP/Infrastructure/CP/UPnPNetworkTracker.cs   |    4 ++
 .../Infrastructure/Dv/GENA/EventSubscription.cs    |    2 +-
 .../Utils/HTTP/HTTPEndpointBinder.cs               |   36 ++++++++++++++++++++
 MediaPortal/Source/Core/UPnP/UPnP.csproj           |    1 +
 7 files changed, 51 insertions(+), 1 deletions(-)
 create mode 100644 MediaPortal/Source/Core/UPnP/Infrastructure/Utils/HTTP/HTTPEndpointBinder.cs

diff --git a/MediaPortal/Source/Core/MediaPortal.Common/Services/MediaManagement/CachedMultiSegmentHttpStream.cs b/MediaPortal/Source/Core/MediaPortal.Common/Services/MediaManagement/CachedMultiSegmentHttpStream.cs
index 70d40ba..df86719 100644
--- a/MediaPortal/Source/Core/MediaPortal.Common/Services/MediaManagement/CachedMultiSegmentHttpStream.cs
+++ b/MediaPortal/Source/Core/MediaPortal.Common/Services/MediaManagement/CachedMultiSegmentHttpStream.cs
@@ -133,6 +133,7 @@ namespace MediaPortal.Common.Services.MediaManagement
       protected void Load_Async()
       {
         HttpWebRequest request = (HttpWebRequest) WebRequest.Create(_url);
+        //TODO : Smeulf -> Bind request to a specific network adapter
         request.Method = "GET";
         request.KeepAlive = true;
         request.AllowAutoRedirect = true;
diff --git a/MediaPortal/Source/Core/UPnP/Infrastructure/CP/DeviceConnection.cs b/MediaPortal/Source/Core/UPnP/Infrastructure/CP/DeviceConnection.cs
index bc32701..6326c0f 100644
--- a/MediaPortal/Source/Core/UPnP/Infrastructure/CP/DeviceConnection.cs
+++ b/MediaPortal/Source/Core/UPnP/Infrastructure/CP/DeviceConnection.cs
@@ -204,6 +204,8 @@ namespace UPnP.Infrastructure.CP
       string message = SOAPHandler.EncodeCall(action, inParams, _rootDescriptor.SSDPRootEntry.UPnPVersion);
 
       HttpWebRequest request = CreateActionCallRequest(sd, action);
+      //Smeulf : Bind request to a specific network adapter
+      request = new UPnP.Infrastructure.Utils.HTTP.HTTPEndpointBinder(sd.RootDescriptor.SSDPRootEntry.PreferredLink.Endpoint.EndPointIPAddress,request).GetRequestWithEndpoint();
       ActionCallState state = new ActionCallState(action, clientState, request);
       state.SetRequestMessage(message);
       lock (_cpData.SyncObj)
diff --git a/MediaPortal/Source/Core/UPnP/Infrastructure/CP/GENA/GENAClientController.cs b/MediaPortal/Source/Core/UPnP/Infrastructure/CP/GENA/GENAClientController.cs
index 1d51e04..e9ae6c6 100644
--- a/MediaPortal/Source/Core/UPnP/Infrastructure/CP/GENA/GENAClientController.cs
+++ b/MediaPortal/Source/Core/UPnP/Infrastructure/CP/GENA/GENAClientController.cs
@@ -235,6 +235,8 @@ namespace UPnP.Infrastructure.CP.GENA
       lock (_cpData.SyncObj)
       {
         HttpWebRequest request = CreateEventSubscribeRequest(serviceDescriptor);
+        //Smeulf : Bind request to a specific network adapter
+        request = new UPnP.Infrastructure.Utils.HTTP.HTTPEndpointBinder(serviceDescriptor.RootDescriptor.SSDPRootEntry.PreferredLink.Endpoint.EndPointIPAddress, request).GetRequestWithEndpoint();
         ChangeEventSubscriptionState state = new ChangeEventSubscriptionState(serviceDescriptor, service, request);
         _pendingCalls.Add(state);
         IAsyncResult result = state.Request.BeginGetResponse(OnSubscribeOrRenewSubscriptionResponseReceived, state);
@@ -256,6 +258,8 @@ namespace UPnP.Infrastructure.CP.GENA
       lock (_cpData.SyncObj)
       {
         HttpWebRequest request = CreateRenewEventSubscribeRequest(subscription);
+        //Smeulf : Bind request to a specific network adapter
+        request = new UPnP.Infrastructure.Utils.HTTP.HTTPEndpointBinder(subscription.ServiceDescriptor.RootDescriptor.SSDPRootEntry.PreferredLink.Endpoint.EndPointIPAddress, request).GetRequestWithEndpoint();
         ChangeEventSubscriptionState state = new ChangeEventSubscriptionState(subscription.ServiceDescriptor, subscription.Service, request);
         _pendingCalls.Add(state);
         IAsyncResult result = state.Request.BeginGetResponse(OnSubscribeOrRenewSubscriptionResponseReceived, state);
@@ -321,6 +325,8 @@ namespace UPnP.Infrastructure.CP.GENA
       lock (_cpData.SyncObj)
       {
         HttpWebRequest request = CreateEventUnsubscribeRequest(subscription);
+        //Smeulf : Bind request to a specific network adapter
+        request = new UPnP.Infrastructure.Utils.HTTP.HTTPEndpointBinder(subscription.ServiceDescriptor.RootDescriptor.SSDPRootEntry.PreferredLink.Endpoint.EndPointIPAddress, request).GetRequestWithEndpoint();
         ChangeEventSubscriptionState state = new ChangeEventSubscriptionState(subscription.ServiceDescriptor, subscription.Service, request);
         _pendingCalls.Add(state);
         IAsyncResult result = state.Request.BeginGetResponse(OnUnsubscribeResponseReceived, state);
diff --git a/MediaPortal/Source/Core/UPnP/Infrastructure/CP/UPnPNetworkTracker.cs b/MediaPortal/Source/Core/UPnP/Infrastructure/CP/UPnPNetworkTracker.cs
index 1ba811e..fdf30d3 100644
--- a/MediaPortal/Source/Core/UPnP/Infrastructure/CP/UPnPNetworkTracker.cs
+++ b/MediaPortal/Source/Core/UPnP/Infrastructure/CP/UPnPNetworkTracker.cs
@@ -284,6 +284,8 @@ namespace UPnP.Infrastructure.CP
       try
       {
         HttpWebRequest request = CreateHttpGetRequest(new Uri(rootEntry.PreferredLink.DescriptionLocation));
+        //Smeulf : Bind request to a specific network adapter
+        request = new UPnP.Infrastructure.Utils.HTTP.HTTPEndpointBinder(rootEntry.PreferredLink.Endpoint.EndPointIPAddress, request).GetRequestWithEndpoint();
         DescriptionRequestState state = new DescriptionRequestState(rd, request);
         lock (_cpData.SyncObj)
           _pendingRequests.Add(state);
@@ -375,6 +377,8 @@ namespace UPnP.Infrastructure.CP
         try
         {
           HttpWebRequest request = CreateHttpGetRequest(new Uri(new Uri(rootDescriptor.SSDPRootEntry.PreferredLink.DescriptionLocation), url));
+          //Smeulf : Bind request to a specific network adapter
+          request = new UPnP.Infrastructure.Utils.HTTP.HTTPEndpointBinder(rootDescriptor.SSDPRootEntry.PreferredLink.Endpoint.EndPointIPAddress, request).GetRequestWithEndpoint();
           state.Request = request;
           IAsyncResult result = request.BeginGetResponse(OnServiceDescriptionReceived, state);
           NetworkHelper.AddTimeout(request, result, PENDING_REQUEST_TIMEOUT * 1000);
diff --git a/MediaPortal/Source/Core/UPnP/Infrastructure/Dv/GENA/EventSubscription.cs b/MediaPortal/Source/Core/UPnP/Infrastructure/Dv/GENA/EventSubscription.cs
index cd5d859..7377968 100644
--- a/MediaPortal/Source/Core/UPnP/Infrastructure/Dv/GENA/EventSubscription.cs
+++ b/MediaPortal/Source/Core/UPnP/Infrastructure/Dv/GENA/EventSubscription.cs
@@ -155,7 +155,7 @@ namespace UPnP.Infrastructure.Dv.GENA
       }
       string callbackURL = e.Current;
       state.PendingCallbackURLs.Remove(callbackURL);
-
+      //TODO : Smeulf => bind this request to a specific network adapter
       HttpWebRequest request = (HttpWebRequest) WebRequest.Create(callbackURL);
       request.Method = "NOTIFY";
       request.KeepAlive = false;
diff --git a/MediaPortal/Source/Core/UPnP/Infrastructure/Utils/HTTP/HTTPEndpointBinder.cs b/MediaPortal/Source/Core/UPnP/Infrastructure/Utils/HTTP/HTTPEndpointBinder.cs
new file mode 100644
index 0000000..13abb92
--- /dev/null
+++ b/MediaPortal/Source/Core/UPnP/Infrastructure/Utils/HTTP/HTTPEndpointBinder.cs
@@ -0,0 +1,36 @@
+﻿//using System;
+//using System.Collections.Generic;
+using System.Net;
+using UPnP.Infrastructure.CP.SSDP;
+
+
+namespace UPnP.Infrastructure.Utils.HTTP
+{
+  class HTTPEndpointBinder
+  {
+    private IPAddress _remoteIpAddress;
+    private HttpWebRequest _request;
+
+    public delegate IPEndPoint BindIPEndPoint(ServicePoint servicePoint,
+      IPEndPoint remoteEndPoint, int retryCount);
+
+    private IPEndPoint BindIPEndPointCallback(ServicePoint servicePoint, 
+                                              IPEndPoint remoteEndPoint, int retryCount)
+    {
+      IPEndPoint ipe = new IPEndPoint(_remoteIpAddress, 0);
+      return ipe;
+    }
+
+    public HTTPEndpointBinder(IPAddress remoteIpAddress, HttpWebRequest request)
+    {
+      _remoteIpAddress = remoteIpAddress;
+      _request = request;
+    }
+
+    public HttpWebRequest GetRequestWithEndpoint()
+    {
+      _request.ServicePoint.BindIPEndPointDelegate = new System.Net.BindIPEndPoint(BindIPEndPointCallback);
+      return _request;
+    }
+  }
+}
diff --git a/MediaPortal/Source/Core/UPnP/UPnP.csproj b/MediaPortal/Source/Core/UPnP/UPnP.csproj
index a6c48c5..f7fbefe 100644
--- a/MediaPortal/Source/Core/UPnP/UPnP.csproj
+++ b/MediaPortal/Source/Core/UPnP/UPnP.csproj
@@ -93,6 +93,7 @@
     <Compile Include="Infrastructure\CP\Exceptions.cs" />
     <Compile Include="Infrastructure\CP\GENA\EventSubscription.cs" />
     <Compile Include="Infrastructure\Dv\CallContext.cs" />
+    <Compile Include="Infrastructure\Utils\HTTP\HTTPEndpointBinder.cs" />
     <Compile Include="Infrastructure\Utils\UDPAsyncReceiveState.cs" />
     <Compile Include="Infrastructure\ILogger.cs" />
     <Compile Include="Infrastructure\Utils\HttpServerHelper.cs" />
-- 
1.7.4.msysgit.0

