studio Odyssey




スタジオ日誌

日誌的なもの

2010.06.22

UPnPサンプル

Written by
しゃちょ
Category
C#

ごく一部から、ちょこ@DCC Sendの、UPnPの部分、まぁ、ポートを開く部分ですが、ここのコードの解説をして欲しいという話があったので、UPnPのコードの話です。

 キーワード的には、C#、ポート、開く、とかポートマッピングとかかなぁ。

 まふ、C#のプログラムに興味のない方は回れ右。とりあえずコードだけあればいいよと言う人はこちら。(UPnPSample.zip)

それ以外の方は、続きを読む。

 というわけで、UPnPのサンプルコードのちょっと解説。

 サンプルコードには、実際に動くコードもあるので、見てもらうとして、コード的には、重要なのはUPnPクラスです。なんか、TcpTableとか、TcpRowとかいうクラスがありますが、それはあんまり気にしないでいいです。UPnPの機能とは関係ないんですよね。それ、現在使ってるポートとかを調べて、ポートをずらす機能に使われてる。

 ともあれ、UPnPクラスです。使い方としては、newして、AddTcpPortMappingか、AddUdpPortMappingを呼び出すだけです。なので、このメソッドから順繰りに見てきます。

public bool AddTcpPortMapping(int port, int duration, string description)
{
    foreach (KeyValuePair<IPAddress, IPAddress> pair in this.NicAddressKeyValuePair)
    {
        if (this.AddTcpPortMapping(pair.Key, pair.Value, port, duration, description))
        {
            return true;
        }
    }

    return false;
}

 ここは、NicAddressKeyValuePairプロパティを使って、ぐるぐる回しながら、AddTcpPortMappingを呼び出しています。何をしているのかっていうと、Nicの設定を列挙して、そこからゲートウェイをもらって、UPnPを飛ばす先を調べているんですね。で、実際の処理は、AddTcpPortMappingのオーバーロードの中。ここの先の呼び出しで、TcpもUdpも同じところに行きます。SOAPメッセージがちょっと変わるだけなんで。

private bool AddPortMapping(IPAddress localAddress, IPAddress remoteAddress, int port, int duration, string description, string protocol)
{
    try
    {
        UPnpSetting upnpSetting = this.GetUPnpSetting(remoteAddress);

        if (upnpSetting != null)
        {
            string result = this.GetSoapResult(
                upnpSetting,
                "AddPortMapping",
                this.CreateSoapBody(String.Format(CultureInfo.InvariantCulture, @"<u:AddPortMapping xmlns:u=""{0}"">
<NewRemoteHost></NewRemoteHost>
<NewExternalPort>{1}</NewExternalPort>
<NewProtocol>{5}</NewProtocol>
<NewInternalPort>{1}</NewInternalPort>
<NewInternalClient>{2}</NewInternalClient>
<NewEnabled>1</NewEnabled>
<NewPortMappingDescription>{3}</NewPortMappingDescription>
<NewLeaseDuration>{4}</NewLeaseDuration>
</u:AddPortMapping>", upnpSetting.ServiceType, port, localAddress, description, duration, protocol)));

            return !String.IsNullOrEmpty(result);
        }
    }
    catch { }

    return false;
}

 結局のところ、ここがすべてのキモで、何をやっているのかというと、UPnPに対応しているネットワーク機器を探して、そのコントロールのアドレスをもらって(GetUPnpSetting)そこに対して、SOAPメッセージを送ってる(GetSoapResult)だけなんですよ。中身は難しそうですけど、やってることはそうでもない。

 UPnP機器がどういうメッセージを送ると何を返すかっていうのは、まぁ、調べないとダメなんでしょうけど...よく見れば、マルチキャストメッセージ送ったりもしてるな...まぁ、この辺は、うーん...こういうもの...としか...

 うーん...全然、説明になってないな...

 以下、コピペ用のコードです。まぁ、UPnPクラスをnewしたら、操作のメソッドを見れば、だいたいどんな風に動くのかはわかるんじゃないかと思うんだけど...ダメかい?

 ググれば、もうちょっとちゃんと説明してくれるサイトもあるよ!きっと!俺もそもそもはググって調べながら書いたんだしね!

using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.IO;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Xml;

namespace UPnPSample
{
    /// <summary>
    /// Firewall(ルーターとか)ポートを開けてもらうためのUPnPのクラス。適当
    /// </summary>
    /// <remarks>
    /// <para>
    /// 結構適当で、いろいろとごちゃごちゃ使うので、ちょっと見にくいかもしれん。
    /// まぁ、拡張する場合は、気をつけて。
    /// </para>
    /// </remarks>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Pn")]
    public sealed class UPnP
    {
        #region constructor
        /// <summary>
        /// UPnP の新しいインスタンスを生成します。
        /// </summary>
        public UPnP()
        {
        }
        #endregion

        #region NicAddressKeyValuePair / NICのIPアドレスをkeyとして、valueにゲートウェイアドレスを持ったKeyValuePairを列挙します。
        /// <summary>
        /// NICのIPアドレスをkeyとして、valueにゲートウェイアドレスを持ったKeyValuePairを列挙します。
        /// </summary>
        /// <remarks>
        /// <para>
        /// 総当たりするための列挙を取得するためのもの。内部的には、yield で。
        /// </para>
        /// </remarks>
        private IEnumerable<KeyValuePair<IPAddress, IPAddress>> NicAddressKeyValuePair
        {
            get
            {
                //NICの列挙
                foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
                {
                    IPInterfaceProperties ipProp = nic.GetIPProperties();

                    if (ipProp != null && ipProp.UnicastAddresses.Count > 0)
                    {
                        IPAddress localAddress = ipProp.UnicastAddresses[0].Address;

                        foreach (GatewayIPAddressInformation gw in ipProp.GatewayAddresses)
                        {
                            yield return new KeyValuePair<IPAddress, IPAddress>(localAddress, gw.Address);
                        }
                    }
                }
            }
        }
        #endregion

        #region GetMultiCastResult / マルチキャストを送信し、リモートからのレスポンスを取得します。
        /// <summary>
        /// マルチキャストを送信し、リモートからのレスポンスを取得します。
        /// </summary>
        /// <param name="remoteAddress">取得するリモートホストアドレス</param>
        /// <returns>取得したマルチキャストの結果</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
        private string GetMultiCastResult(IPAddress remoteAddress)
        {
            string query = @"M-SEARCH * HTTP/1.1
Host:239.255.255.250:1900
ST:upnp:rootdevice
Man:""ssdp:discover""
MX:3

";
            Socket client = null;

            try
            {
                client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

                IPEndPoint endPoint = new IPEndPoint(remoteAddress, 1900);

                client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 5000);

                byte[] q = Encoding.ASCII.GetBytes(query);

                client.SendTo(q, q.Length, SocketFlags.None, endPoint);

                EndPoint senderEP = (EndPoint)(new IPEndPoint(IPAddress.Any, 0));

                byte[] data = new byte[1024];
                int length = client.ReceiveFrom(data, ref senderEP);

                if (length > 0)
                {
                    return Encoding.ASCII.GetString(data);
                }
                else
                {
                    return null;
                }
            }
            finally
            {
                if (client != null)
                {
                    client.Close();
                }
            }
        }
        #endregion

        #region GetServiceLocation / リモートから、UPnPを使って、利用可能なサービスの置かれているUriを取得します。
        /// <summary>
        /// リモートから、UPnPを使って、利用可能なサービスの置かれているUriを取得します。
        /// </summary>
        /// <param name="remoteAddress">リモートのアドレス</param>
        /// <returns>利用可能なサービスのSOAPメッセージ</returns>
        private Uri GetServiceLocation(IPAddress remoteAddress)
        {
            try
            {
                string multiCastResult = this.GetMultiCastResult(remoteAddress);

                if (!String.IsNullOrEmpty(multiCastResult))
                {
                    string location = null;

                    string[] parts = multiCastResult.Split(new string[] { System.Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);

                    foreach (string part in parts)
                    {
                        //あんまり意味ない指定だけど、念のため
                        if (part.ToUpperInvariant().StartsWith("LOCATION", StringComparison.OrdinalIgnoreCase))
                        {
                            location = part.Substring(part.IndexOf(':') + 1);
                            break;
                        }
                    }

                    if (!String.IsNullOrEmpty(location))
                    {
                        return new Uri(location);
                    }
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.Message);
                throw;
            }

            return null;
        }
        #endregion

        #region GetServices / uriからサービスのXMLを取得します。
        /// <summary>
        /// uri からサービスのXMLを取得します。
        /// </summary>
        /// <param name="uri">取得するuri</param>
        /// <returns>取得したサービスのXML。取得出来なかった場合は null 。</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
        private string GetServices(Uri uri)
        {
            using (WebClient webClient = new WebClient())
            {
                try
                {
                    return webClient.DownloadString(uri);
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(ex.Message);
                    throw;
                }
            }
        }
        #endregion

        #region class UPnpSetting / GetUPnpSetting の戻り値として利用されるクラス
        /// <summary>
        /// GetControlUrl の戻り値として利用されるクラス
        /// </summary>
        private sealed class UPnpSetting
        {
            /// <summary>
            /// UPnpSetting の新しいインスタンスを生成します。
            /// </summary>
            /// <param name="serviceLocation">サービスの存在するUri</param>
            /// <param name="services">サービスの内容のXML</param>
            /// <param name="serviceType">サービスのタイプ</param>
            /// <param name="controlUrl">コントロールUri</param>
            public UPnpSetting(Uri serviceLocation, string services, string serviceType, string controlUrl)
            {
                this.ServiceLocation = serviceLocation;
                this.Services = services;
                this.ServiceType = serviceType;
                this.ControlUrl = controlUrl;
            }

            /// <summary>
            /// サービスのロケーションを取得します。
            /// </summary>
            public Uri ServiceLocation { get; private set; }

            /// <summary>
            /// サービスのXMLを取得します。
            /// </summary>
            public string Services { get; private set; }

            /// <summary>
            /// サービスタイプを取得します。
            /// </summary>
            public string ServiceType { get; private set; }

            /// <summary>
            /// コントロールURLを取得します。
            /// </summary>
            public string ControlUrl { get; private set; }

            /// <summary>
            /// サービスに対するリクエストに利用するUriを取得します。
            /// </summary>
            public Uri RequestUri
            {
                get
                {
                    return new Uri(this.ServiceLocation, this.ControlUrl);
                }
            }
        }
        #endregion

        #region GetUPnpSetting / リモートに指定されたアドレスから、サービスの設定を取得します。
        /// <summary>
        /// リモートに指定されたアドレスから、サービスの設定を取得します。
        /// </summary>
        /// <param name="remoteAddress">サービスの設定を取得するリモートのアドレス</param>
        /// <returns>取得したサービスの設定。取得出来なかった場合は null 。</returns>
        private UPnpSetting GetUPnpSetting(IPAddress remoteAddress)
        {
            Uri uri = this.GetServiceLocation(remoteAddress);

            if (uri != null)
            {
                string services = this.GetServices(uri);

                if (!String.IsNullOrEmpty(services))
                {
                    foreach (string serviceType in new string[]
                    {
                        "urn:schemas-upnp-org:service:WANIPConnection:1",
                        "urn:schemas-upnp-org:service:WANPPPConnection:1",
                    })
                    {
                        int serviceTypeIndex = services.IndexOf(serviceType, StringComparison.OrdinalIgnoreCase);

                        if (serviceTypeIndex != -1)
                        {
                            string controlUrl = services.Substring(serviceTypeIndex);

                            controlUrl = controlUrl.Substring(controlUrl.IndexOf("<controlURL>", StringComparison.OrdinalIgnoreCase) + ("<controlURL>").Length);
                            controlUrl = controlUrl.Substring(0, controlUrl.IndexOf("</controlURL>", StringComparison.OrdinalIgnoreCase));

                            return new UPnpSetting(uri, services, serviceType, controlUrl);
                        }
                    }
                }
            }

            return null;
        }
        #endregion

        #region CreateSoapBody / SOAPのbody部分を追加するだけの、手抜き
        /// <summary>
        /// SOAPのbody部分を追加するだけの、手抜き
        /// </summary>
        /// <param name="body">BODYに突っ込む文字列</param>
        /// <returns>生成された文字列</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
        private byte[] CreateSoapBody(string body)
        {
            string soapMessage = String.Format(CultureInfo.InvariantCulture, @"<s:Envelope xmlns:s=""http://schemas.xmlsoap.org/soap/envelope/"" s:encodingStyle=""http://schemas.xmlsoap.org/soap/encoding/"">
<s:Body>
{0}
</s:Body>
</s:Envelope>", body);

            return UTF8Encoding.ASCII.GetBytes(soapMessage);
        }
        #endregion

        #region GetSoapResult / SOAPメッセージを送信し、その結果を取得します。
        /// <summary>
        /// SOAPメッセージを送信し、その結果を取得します。
        /// </summary>
        /// <param name="upnpSetting">UPnPの設定</param>
        /// <param name="methodName">呼び出すメソッド</param>
        /// <param name="soapMessage">SOAPメッセージ</param>
        /// <returns>受信した文字列。HttpStatusCode が 200 でない時等、失敗した時は null 。</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
        private string GetSoapResult(UPnpSetting upnpSetting, string methodName, byte[] soapMessage)
        {
            WebRequest webRequest = WebRequest.Create(upnpSetting.RequestUri);

            webRequest.Method = "POST";
            webRequest.Headers.Add("SOAPAction", String.Format(CultureInfo.InvariantCulture, @"""{0}#{1}""", upnpSetting.ServiceType, methodName));

            webRequest.ContentType = @"text/xml;charset=""utf-8""";
            webRequest.ContentLength = soapMessage.Length;

            using (Stream stream = webRequest.GetRequestStream())
            {
                stream.Write(soapMessage, 0, soapMessage.Length);
                stream.Flush();
                stream.Close();
            }

            HttpWebResponse webResponse = webRequest.GetResponse() as HttpWebResponse;
            string result = null;

            if (webResponse.StatusCode == HttpStatusCode.OK)
            {
                using (StreamReader sr = new System.IO.StreamReader(webResponse.GetResponseStream()))
                {
                    result = sr.ReadToEnd();
                    sr.Close();
                }
            }

            return result;
        }
        #endregion

        #region GetWanAddress / UPnpを利用して、WAN側のIPアドレスを取得します。
        /// <summary>
        /// UPnpを利用して、WAN側のIPアドレスを取得します。
        /// </summary>
        /// <returns>取得したIPアドレス。</returns>
        public IPAddress GetWanAddress()
        {
            foreach (KeyValuePair<IPAddress, IPAddress> pair in this.NicAddressKeyValuePair)
            {
                IPAddress result = this.GetWanAddress(pair.Value);

                if (result != null)
                {
                    return result;
                }
            }

            return null;
        }

        /// <summary>
        /// UPnpを利用して、WAN側のIPアドレスを取得します。
        /// </summary>
        /// <returns>取得したIPアドレス。</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        public IPAddress GetWanAddress(IPAddress remoteAddress)
        {
            try
            {
                UPnpSetting upnpSetting = this.GetUPnpSetting(remoteAddress);

                if (upnpSetting != null)
                {
                    string result = this.GetSoapResult(
                        upnpSetting,
                        "GetExternalIPAddress",
                        this.CreateSoapBody(String.Format(CultureInfo.InvariantCulture, @"<u:GetExternalIPAddress xmlns:u=""{0}""></u:GetExternalIPAddress>", upnpSetting.ServiceType)));

                    if (!String.IsNullOrEmpty(result))
                    {
                        XmlDocument doc = new XmlDocument();
                        doc.LoadXml(result);

                        string extrenalAddress = doc.GetElementsByTagName("NewExternalIPAddress")[0].InnerText;

                        return IPAddress.Parse(extrenalAddress);
                    }
                }
            }
            catch { }

            return null;
        }
        #endregion

        #region AddTcpPortMapping / UPnPを利用して、自身のIPアドレスに対して、TCPのポートマッピングを追加します。
        /// <summary>
        /// UPnPを利用して、自身のIPアドレスに対して、TCPのポートマッピングを追加します。
        /// </summary>
        /// <param name="port">追加するポート</param>
        /// <param name="duration">設定の有効時間(秒)無制限は0</param>
        /// <param name="description">設定の説明</param>
        /// <returns>正常に追加された時は <c>true</c> 。</returns>
        public bool AddTcpPortMapping(int port, int duration, string description)
        {
            foreach (KeyValuePair<IPAddress, IPAddress> pair in this.NicAddressKeyValuePair)
            {
                if (this.AddTcpPortMapping(pair.Key, pair.Value, port, duration, description))
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// UPnPを利用して、指定されたIPアドレスに対して、指定したリモートにTCPのポートマッピングを追加します。
        /// </summary>
        /// <param name="localAddress">ポートマップするアドレス</param>
        /// <param name="remoteAddress">ポートマップを設定するリモートアドレス</param>
        /// <param name="port">追加するポート</param>
        /// <param name="duration">設定の有効時間(秒)無制限は0</param>
        /// <param name="description">設定の説明</param>
        /// <returns>正常に追加された時は <c>true</c> 。</returns>
        public bool AddTcpPortMapping(IPAddress localAddress, IPAddress remoteAddress, int port, int duration, string description)
        {
            return AddPortMapping(localAddress, remoteAddress, port, duration, description, "TCP");
        }
        #endregion

        #region AddUdpPortMapping / UPnPを利用して、自身のIPアドレスに対して、UDPのポートマッピングを追加します。
        /// <summary>
        /// UPnPを利用して、自身のIPアドレスに対して、UDPのポートマッピングを追加します。
        /// </summary>
        /// <param name="port">追加するポート</param>
        /// <param name="duration">設定の有効時間(秒)無制限は0</param>
        /// <param name="description">設定の説明</param>
        /// <returns>正常に追加された時は <c>true</c> 。</returns>
        public bool AddUdpPortMapping(int port, int duration, string description)
        {
            foreach (KeyValuePair<IPAddress, IPAddress> pair in this.NicAddressKeyValuePair)
            {
                if (this.AddUdpPortMapping(pair.Key, pair.Value, port, duration, description))
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// UPnPを利用して、指定されたIPアドレスに対して、指定したリモートにUDOのポートマッピングを追加します。
        /// </summary>
        /// <param name="localAddress">ポートマップするアドレス</param>
        /// <param name="remoteAddress">ポートマップを設定するリモートアドレス</param>
        /// <param name="port">追加するポート</param>
        /// <param name="duration">設定の有効時間(秒)無制限は0</param>
        /// <param name="description">設定の説明</param>
        /// <returns>正常に追加された時は <c>true</c> 。</returns>
        public bool AddUdpPortMapping(IPAddress localAddress, IPAddress remoteAddress, int port, int duration, string description)
        {
            return AddPortMapping(localAddress, remoteAddress, port, duration, description, "UDP");
        }
        #endregion

        #region AddPortMapping / UPnPを利用して、指定されたIPアドレスに対して、指定したリモートにTCPのポートマッピングを追加します。
        /// <summary>
        /// UPnPを利用して、指定されたIPアドレスに対して、指定したリモートにTCPのポートマッピングを追加します。
        /// </summary>
        /// <param name="localAddress">ポートマップするアドレス</param>
        /// <param name="remoteAddress">ポートマップを設定するリモートアドレス</param>
        /// <param name="port">追加するポート</param>
        /// <param name="duration">設定の有効時間(秒)無制限は0</param>
        /// <param name="description">設定の説明</param>
        /// <param name="protocol">プロトコル</param>
        /// <returns>正常に追加された時は <c>true</c> 。</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        private bool AddPortMapping(IPAddress localAddress, IPAddress remoteAddress, int port, int duration, string description, string protocol)
        {
            try
            {
                UPnpSetting upnpSetting = this.GetUPnpSetting(remoteAddress);

                if (upnpSetting != null)
                {
                    string result = this.GetSoapResult(
                        upnpSetting,
                        "AddPortMapping",
                        this.CreateSoapBody(String.Format(CultureInfo.InvariantCulture, @"<u:AddPortMapping xmlns:u=""{0}"">
<NewRemoteHost></NewRemoteHost>
<NewExternalPort>{1}</NewExternalPort>
<NewProtocol>{5}</NewProtocol>
<NewInternalPort>{1}</NewInternalPort>
<NewInternalClient>{2}</NewInternalClient>
<NewEnabled>1</NewEnabled>
<NewPortMappingDescription>{3}</NewPortMappingDescription>
<NewLeaseDuration>{4}</NewLeaseDuration>
</u:AddPortMapping>", upnpSetting.ServiceType, port, localAddress, description, duration, protocol)));

                    return !String.IsNullOrEmpty(result);
                }
            }
            catch { }

            return false;
        }
        #endregion

        #region CreatePortMappingTable / ポートマップの状態を教えるためのデータテーブルを作る
        /// <summary>
        /// ポートマップの状態を教えるためのデータテーブルを作る
        /// </summary>
        /// <returns>生成されたポートマップテーブル。空。</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
        private DataTable CreatePortMappingTable()
        {
            DataTable result = new DataTable();
            result.Locale = CultureInfo.CurrentCulture;

            result.Columns.Add("RemoteAddress", typeof(string));
            result.Columns.Add("Index", typeof(int));
            result.Columns.Add("NewRemoteHost", typeof(string));
            result.Columns.Add("NewExternalPort", typeof(int));
            result.Columns.Add("NewProtocol", typeof(string));
            result.Columns.Add("NewInternalPort", typeof(int));
            result.Columns.Add("NewInternalClient", typeof(string));
            result.Columns.Add("NewEnabled", typeof(string));
            result.Columns.Add("NewPortMappingDescription", typeof(string));
            result.Columns.Add("NewLeaseDuration", typeof(int));

            return result;
        }
        #endregion

        #region GetPortMapping / 設定されているポートマップの一覧を取得します。
        /// <summary>
        /// 設定されているポートマップの一覧を取得します。
        /// </summary>
        /// <returns>取得したポートマップのテーブル</returns>
        public DataTable GetPortMapping()
        {
            DataTable result = this.CreatePortMappingTable();

            foreach (KeyValuePair<IPAddress, IPAddress> pair in this.NicAddressKeyValuePair)
            {
                DataTable temp = this.GetPortMapping(pair.Value);

                if (temp != null)
                {
                    foreach (DataRow row in temp.Rows)
                    {
                        result.Rows.Add(row.ItemArray);
                    }
                }
            }

            return result;
        }

        /// <summary>
        /// 指定されたリモートに設定されているポートマップの一覧を取得します。
        /// </summary>
        /// <param name="remoteAddress">取得するリモート</param>
        /// <returns>生成されたポートマップのテーブル</returns>
        public DataTable GetPortMapping(IPAddress remoteAddress)
        {
            DataTable result = this.CreatePortMappingTable();
            int index = 0;

            while (true)
            {
                DataTable temp = this.GetPortMapping(remoteAddress, index++);

                if (temp == null || temp.Rows.Count == 0)
                {
                    break;
                }
                else
                {
                    foreach (DataRow row in temp.Rows)
                    {
                        result.Rows.Add(row.ItemArray);
                    }
                }
            }

            return result;
        }

        /// <summary>
        /// 指定されたリモート、指定されたインデックスにあるポートマップのテーブルを取得します。
        /// </summary>
        /// <param name="remoteAddress">取得するリモート</param>
        /// <param name="index">取得するインデックス</param>
        /// <returns>生成されたポートマップのテーブル</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        public DataTable GetPortMapping(IPAddress remoteAddress, int index)
        {
            DataTable result = this.CreatePortMappingTable();

            try
            {
                UPnpSetting upnpSetting = this.GetUPnpSetting(remoteAddress);

                if (upnpSetting != null)
                {
                    string revMessage = this.GetSoapResult(
                        upnpSetting,
                        "GetGenericPortMappingEntry",
                        this.CreateSoapBody(String.Format(CultureInfo.InvariantCulture, @"<u:GetGenericPortMappingEntry xmlns:u=""{0}"">
<NewPortMappingIndex>{1}</NewPortMappingIndex>
</u:GetGenericPortMappingEntry>", upnpSetting.ServiceType, index)));

                    if (!String.IsNullOrEmpty(revMessage))
                    {
                        XmlDocument doc = new XmlDocument();
                        doc.LoadXml(revMessage);

                        DataSet dataSet = new DataSet();
                        dataSet.Locale = CultureInfo.CurrentCulture;

                        using (MemoryStream ms = new MemoryStream())
                        {
                            doc.Save(ms);
                            ms.Seek(0, SeekOrigin.Begin);

                            XmlTextReader reader = new XmlTextReader(ms);
                            dataSet.ReadXml(reader, XmlReadMode.Auto);
                            reader.Close();
                        }

                        if (dataSet.Tables.Contains("GetGenericPortMappingEntryResponse"))
                        {
                            DataTable sourceTable = dataSet.Tables["GetGenericPortMappingEntryResponse"];

                            foreach (DataRow sourceRow in sourceTable.Rows)
                            {
                                DataRow newRow = result.NewRow();

                                newRow["RemoteAddress"] = remoteAddress.ToString();
                                newRow["Index"] = index;
                                newRow["NewRemoteHost"] = sourceRow["NewRemoteHost"];
                                newRow["NewExternalPort"] = sourceRow["NewExternalPort"];
                                newRow["NewProtocol"] = sourceRow["NewProtocol"];
                                newRow["NewInternalPort"] = sourceRow["NewInternalPort"];
                                newRow["NewInternalClient"] = sourceRow["NewInternalClient"];
                                newRow["NewEnabled"] = sourceRow["NewEnabled"];
                                newRow["NewPortMappingDescription"] = sourceRow["NewPortMappingDescription"];
                                newRow["NewLeaseDuration"] = sourceRow["NewLeaseDuration"];

                                result.Rows.Add(newRow);
                            }
                        }
                    }
                }
            }
            catch { }

            return result;
        }
        #endregion

        #region DeleteTcpPortMapping / TCPの指定されたポートマップを削除します。
        /// <summary>
        /// TCPの指定されたポートマップを削除します。
        /// </summary>
        /// <param name="port">削除するポート</param>
        /// <returns>正常に削除されれば <c>true</c> 。</returns>
        public bool DeleteTcpPortMapping(int port)
        {
            foreach (KeyValuePair<IPAddress, IPAddress> pair in this.NicAddressKeyValuePair)
            {
                if (this.DeleteTcpPortMapping(pair.Value, port))
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// TCPの指定されたリモートのポートのマップを削除します。
        /// </summary>
        /// <param name="remoteAddress">削除するリモート</param>
        /// <param name="port">削除するポート</param>
        /// <returns>正常に削除されれば <c>true</c> 。</returns>
        public bool DeleteTcpPortMapping(IPAddress remoteAddress, int port)
        {
            return DeletePortMapping(remoteAddress, port, "TCP");
        }
        #endregion

        #region DeleteUdpPortMapping / UDPの指定されたポートのポートマップを削除します。
        /// <summary>
        /// UDPの指定されたポートのポートマップを削除します。
        /// </summary>
        /// <param name="port">削除するポート</param>
        /// <returns>削除されれば、<c>true</c> 。</returns>
        public bool DeleteUdpPortMapping(int port)
        {
            foreach (KeyValuePair<IPAddress, IPAddress> pair in this.NicAddressKeyValuePair)
            {
                if (this.DeleteUdpPortMapping(pair.Value, port))
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// 指定されたリモートの、UDPのポートマップを削除します。
        /// </summary>
        /// <param name="remoteAddress">削除するリモート</param>
        /// <param name="port">削除するポート</param>
        /// <returns>削除されれば <c>true</c> 。</returns>
        public bool DeleteUdpPortMapping(IPAddress remoteAddress, int port)
        {
            return DeletePortMapping(remoteAddress, port, "UDP");
        }
        #endregion

        #region DeletePortMapping / 指定されたリモート、ポート、プロトコルのマッピングを削除します。
        /// <summary>
        /// 指定されたリモート、ポート、プロトコルのマッピングを削除します。
        /// </summary>
        /// <param name="remoteAddress">削除するリモート</param>
        /// <param name="port">削除するポート</param>
        /// <param name="protocol">削除するプロトコル</param>
        /// <returns>正常に削除されれば <c>true</c> 。</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        private bool DeletePortMapping(IPAddress remoteAddress, int port, string protocol)
        {
            try
            {
                UPnpSetting upnpSetting = this.GetUPnpSetting(remoteAddress);

                if (upnpSetting != null)
                {
                    string result = this.GetSoapResult(
                        upnpSetting,
                        "DeletePortMapping",
                        this.CreateSoapBody(String.Format(CultureInfo.InvariantCulture, @"<u:DeletePortMapping xmlns:u=""{0}"">
<NewRemoteHost></NewRemoteHost>
<NewExternalPort>{1}</NewExternalPort>
<NewProtocol>{2}</NewProtocol>
</u:DeletePortMapping>", upnpSetting.ServiceType, port, protocol)));

                    return !String.IsNullOrEmpty(result);
                }
            }
            catch { }

            return false;
        }
        #endregion
    }
}

 なげぇ。DataRepeaterのコード、超えたか?


トラックバックURL

http://blog.studio-odyssey.net/cgi-bin/mt/mt-tb.cgi/408


コメントする