public bool AddPortMapping(IUPnPUpdater upnp, PortMapping mapping)
        {
            UPnPFunction func = new UPnPFunction();
            func.Name = "AddPortMapping";
            func.Service = this;

            func.Arguments.Add("NewRemoteHost", (mapping.RemoteHost != null ? mapping.RemoteHost : string.Empty));
            func.Arguments.Add("NewExternalPort", mapping.ExternalPort.ToString());
            func.Arguments.Add("NewProtocol", mapping.Protocol);
            func.Arguments.Add("NewInternalPort", mapping.InternalPort.ToString());
            func.Arguments.Add("NewInternalClient", mapping.InternalHost);
            func.Arguments.Add("NewEnabled", (mapping.Enable ? "1" : "0"));
            func.Arguments.Add("NewPortMappingDescription", mapping.Description);
            func.Arguments.Add("NewLeaseDuration", mapping.LeaseDuration.ToString());

            FmdcEventArgs e = new FmdcEventArgs(Actions.UPnPFunctionCall, func);
            upnp.FireUpdateBase(e);
            return e.Handled;
        }
        /// <summary>
        /// This action retrieves the value of the external IP address on this connection instance.
        /// </summary>
        /// <returns>External IP</returns>
        public System.Net.IPAddress GetExternalIPAddress(IUPnPUpdater upnp)
        {
            UPnPFunction func = new UPnPFunction();
            func.Name = "GetExternalIPAddress";
            func.Service = this;

            func.Arguments.Add("NewExternalIPAddress", string.Empty);

            FmdcEventArgs e = new FmdcEventArgs(Actions.UPnPFunctionCall, func);
            upnp.FireUpdateBase(e);
            if (e.Handled)
            {
                func = e.Data as UPnPFunction;
                if (func != null)
                {
                    try
                    {
                        return System.Net.IPAddress.Parse(func.Arguments["NewExternalIPAddress"]);
                    }
                    catch { }
                }
            }
            return null;
        }
        /// <summary>
        /// This action reports the Static Port Mapping specified by the unique tuple of RemoteHost, ExternalPort and PortMappingProtocol.
        /// </summary>
        /// <param name="mapping"></param>
        /// <returns></returns>
        public bool GetSpecificPortMappingEntry(IUPnPUpdater upnp, ref PortMapping mapping)
        {
            UPnPFunction func = new UPnPFunction();
            func.Name = "GetSpecificPortMappingEntry";
            func.Service = this;

            func.Arguments.Add("NewRemoteHost", (mapping.RemoteHost != null ? mapping.RemoteHost : string.Empty));
            func.Arguments.Add("NewExternalPort", mapping.ExternalPort.ToString());
            func.Arguments.Add("NewProtocol", mapping.Protocol);
            func.Arguments.Add("NewInternalPort", mapping.InternalPort.ToString());
            func.Arguments.Add("NewInternalClient", string.Empty);
            func.Arguments.Add("NewEnabled", string.Empty);
            func.Arguments.Add("NewPortMappingDescription", string.Empty);
            func.Arguments.Add("NewLeaseDuration", string.Empty);

            FmdcEventArgs e = new FmdcEventArgs(Actions.UPnPFunctionCall, func);
            upnp.FireUpdateBase(e);
            if (e.Handled)
            {
                func = e.Data as UPnPFunction;
                if (func != null)
                {
                    string str = func.Arguments["NewRemoteHost"];
                    if (!string.IsNullOrEmpty(str))
                        mapping.RemoteHost = str;
                    str = func.Arguments["NewExternalPort"];
                    if (!string.IsNullOrEmpty(str))
                    {
                        try
                        {
                            mapping.ExternalPort = int.Parse(str);
                        }
                        catch { }
                    }
                    str = func.Arguments["NewProtocol"];
                    if (!string.IsNullOrEmpty(str))
                        mapping.Protocol = str;
                    str = func.Arguments["NewInternalPort"];
                    if (!string.IsNullOrEmpty(str))
                    {
                        try
                        {
                            mapping.InternalPort = int.Parse(str);
                        }
                        catch { }
                    }
                    str = func.Arguments["NewInternalClient"];
                    if (!string.IsNullOrEmpty(str))
                        mapping.InternalHost = str;
                    str = func.Arguments["NewEnabled"];
                    if (!string.IsNullOrEmpty(str))
                    {
                        switch (str)
                        {
                            case "1":
                                mapping.Enable = true;
                                break;
                            case "0":
                                mapping.Enable = false;
                                break;
                        }
                    }
                    str = func.Arguments["NewPortMappingDescription"];
                    if (!string.IsNullOrEmpty(str))
                        mapping.Description = str;
                    str = func.Arguments["NewLeaseDuration"];
                    if (!string.IsNullOrEmpty(str))
                    {
                        try
                        {
                            mapping.LeaseDuration = int.Parse(str);
                        }
                        catch { }
                    }
                }
            }
            return e.Handled;
        }
        /// <summary>
        /// This action deletes a previously instantiated port mapping. 
        /// As each entry is deleted, the array is compacted, and the evented variable PortMappingNumberOfEntries is decremented.
        /// </summary>
        /// <param name="upnp"></param>
        /// <returns></returns>
        public bool DeletePortMapping(IUPnPUpdater upnp, PortMapping mapping)
        {
            UPnPFunction func = new UPnPFunction();
            func.Name = "DeletePortMapping";
            func.Service = this;

            func.Arguments.Add("NewRemoteHost", (mapping.RemoteHost != null ? mapping.RemoteHost : string.Empty));
            func.Arguments.Add("NewExternalPort", mapping.ExternalPort.ToString());
            func.Arguments.Add("NewProtocol", mapping.Protocol);

            FmdcEventArgs e = new FmdcEventArgs(Actions.UPnPFunctionCall, func);
            upnp.FireUpdateBase(e);
            return e.Handled;
        }