using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Collections.Generic;
namespace TCMPortMapper
{
class MiniUPnP
{
public const int UPNPCOMMAND_SUCCESS = 0;
public const int UPNPCOMMAND_UNKNOWN_ERROR = -1;
public const int UPNPCOMMAND_INVALID_ARGS = -2;
public const int MINIUPNPC_URL_MAXSIZE = 128;
[StructLayout(LayoutKind.Sequential)]
public unsafe struct UPNPDev
{
public IntPtr pNext;
public String descURL;
public String st;
public fixed byte buffer[2];
public UPNPDev Next
{
get { return (UPNPDev)Marshal.PtrToStructure(pNext, typeof(UPNPDev)); }
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct UPNPUrls
{
public String controlURL;
public String ipcondescURL;
public String controlURL_CIF;
}
///
/// This structure is used to avoid a SystemAccessViolation,
/// and to prevent corruption of the process' memory.
/// See issue #2 for further discussion.
///
[StructLayout(LayoutKind.Sequential)]
public unsafe struct UPNPUrls_2
{
public char *controlURL;
public char *ipcondescURL;
public char *controlURL_CIF;
}
[StructLayout(LayoutKind.Sequential, Size = 1796, CharSet = CharSet.Ansi)]
public struct IGDdatas
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MINIUPNPC_URL_MAXSIZE)]
private String cureltname;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MINIUPNPC_URL_MAXSIZE)]
public String urlbase;
private Int32 level;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MINIUPNPC_URL_MAXSIZE)]
public String controlurl_CIF;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MINIUPNPC_URL_MAXSIZE)]
private String eventsuburl_CIF;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MINIUPNPC_URL_MAXSIZE)]
private String scpdurl_CIF;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MINIUPNPC_URL_MAXSIZE)]
private String servicetype_CIF;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MINIUPNPC_URL_MAXSIZE)]
public String controlurl;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MINIUPNPC_URL_MAXSIZE)]
private String eventsuburl;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MINIUPNPC_URL_MAXSIZE)]
public String scpdurl;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MINIUPNPC_URL_MAXSIZE)]
private String serviceType;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MINIUPNPC_URL_MAXSIZE)]
private String controlurl_tmp;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MINIUPNPC_URL_MAXSIZE)]
private String eventsuburl_tmp;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MINIUPNPC_URL_MAXSIZE)]
private String scpdurl_tmp;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MINIUPNPC_URL_MAXSIZE)]
private String servicetype_tmp;
public String ServiceType
{
get { return serviceType; }
set { serviceType = value; }
}
}
///
/// Discover UPnP devices on the network.
/// The discovered devices are returned as a chained list.
/// It is up to the caller to free the list with freeUPNPDevlist().
/// If available, device list will be obtained from MiniSSDPd.
///
///
/// Delay (in milliseconds) is the maximum time for waiting any device response.
///
///
/// If NULL, default multicast interface for sending SSDP discover packets will be used.
///
///
/// If null, default path for minissdpd socket will be used.
///
///
/// A pointer to a UPNPDev structure. Free this when done.
/// Use the PtrToUPNPDev method to convert to a UPNPDev structure.
///
[DllImport("miniupnp.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr upnpDiscover([In] int delay,
[In] String multicastif,
[In] String minissdpdsock);
[DllImport("miniupnp.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr upnpDiscover([In] int delay,
[In] IntPtr multicastif,
[In] String minissdpdsock);
[DllImport("miniupnp.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr upnpDiscover([In] int delay,
[In] String multicastif,
[In] IntPtr minissdpdsock);
[DllImport("miniupnp.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr upnpDiscover([In] int delay,
[In] IntPtr multicastif,
[In] IntPtr minissdpdsock);
///
/// frees list returned by upnpDiscover()
///
///
/// IntPtr (pointer to UPNPDev structure) as returned by upnpDiscover().
///
[DllImport("miniupnp.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void freeUPNPDevlist([In] IntPtr devlistP);
///
/// Used when skipping the discovery process.
/// Return value:
/// 0 - Not OK
/// 1 - OK
///
///
///
///
///
///
///
[DllImport("miniupnp.dll", CallingConvention = CallingConvention.Cdecl)]
public unsafe static extern int UPNP_GetIGDFromUrl([In] String rootDescUrl,
[In] UPNPUrls_2 *urls,
[In, Out] ref IGDdatas datas,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] byte[] lanAddr,
[In] int lanAddrLength);
[DllImport("miniupnp.dll", CallingConvention = CallingConvention.Cdecl)]
public unsafe static extern void FreeUPNPUrls([In] UPNPUrls_2 *urls);
///
/// Extracts the external IP address.
///
///
///
///
/// The array to copy the external IP address bytes into.
/// The array must be 16 bytes in length.
///
///
/// 0: SUCCESS
/// NON ZERO: ERROR Either a UPnP error code or an unknown error.
///
/// Possible UPnP Errors:
/// 402 Invalid Args - See UPnP Device Architecture section on Control.
/// 501 Action Failed - See UPnP Device Architecture section on Control.
///
[DllImport("miniupnp.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int UPNP_GetExternalIPAddress([In] String controlURL,
[In] String serviceType,
[In, Out, MarshalAs(UnmanagedType.LPArray, SizeConst = 16)] byte[] externalIPAddr);
[DllImport("miniupnp.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int UPNP_GetExternalIPAddress([In] String controlURL,
[In, MarshalAs(UnmanagedType.LPArray, SizeConst = MINIUPNPC_URL_MAXSIZE)] byte[] serviceType,
[In, Out, MarshalAs(UnmanagedType.LPArray, SizeConst = 16)] byte[] externalIPAddr);
///
/// Description forthcoming...
///
///
///
///
///
///
///
///
///
///
///
///
///
/// UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR or a UPnP Error Code.
///
/// Possible UPNP Error codes:
/// 402 Invalid Args - See UPnP Device Architecture section on Control
/// 713 SpecifiedArrayIndexInvalid - The specified array index is out of bounds
///
[DllImport("miniupnp.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int UPNP_GetGenericPortMappingEntry([In] String controlURL,
[In] String serviceType,
[In] [MarshalAs(UnmanagedType.LPArray, SizeConst = 6)] byte[] index,
[MarshalAs(UnmanagedType.LPArray, SizeConst = 6)] byte[] extPort,
[MarshalAs(UnmanagedType.LPArray, SizeConst = 16)] byte[] intClient,
[MarshalAs(UnmanagedType.LPArray, SizeConst = 6)] byte[] intPort,
[MarshalAs(UnmanagedType.LPArray, SizeConst = 4)] byte[] protocol,
[MarshalAs(UnmanagedType.LPArray, SizeConst = 80)] byte[] desc,
[MarshalAs(UnmanagedType.LPArray, SizeConst = 6)] byte[] enabled,
[MarshalAs(UnmanagedType.LPArray, SizeConst = 64)] byte[] rHost,
[MarshalAs(UnmanagedType.LPArray, SizeConst = 16)] byte[] duration);
///
/// Adds a UPnP port mapping using the given information.
///
///
///
///
///
///
///
///
///
/// Returns values:
/// Zero: SUCCESS
/// Non-Zero: ERROR. Either a UPnP error code or an unknown error.
///
/// List of possible UPnP errors:
/// 402 - Invalid Args
/// 501 - Action Failed
/// 715 - WildCardNotPermittedInSrcIP
/// 716 - WildCardNotPermittedInExtPort
/// 718 - ConflictInMappingEntry
/// The port mapping entry specified conflicts with a mapping assigned previously to another client
/// 724 - SamePortValueRequired
/// Internal and External port values must be the same
/// 725 - OnlyPermanentLeasesSupported
/// The NAT implementation only supports permanent lease times on port mappings
/// 726 - RemoteHostOnlySupportsWildcard
/// RemoteHost must be a wildcard and cannot be a specific IP address or DNS name
/// 727 - ExternalPortOnlySupportsWildcard
/// ExternalPort must be a wildcard and cannot be a specific port value
///
[DllImport("miniupnp.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int UPNP_AddPortMapping([In] String controlURL,
[In] String serviceType,
[In] String externalPort,
[In] String internalPort,
[In] String internalClient,
[In] String description,
[In] String protocol);
///
/// Deletes a UPnP port mapping with the given information.
///
///
///
///
///
///
/// Return values:
/// Zero: SUCCESS
/// Non-Zero: ERROR. Either a UPnP error code or an undefined error.
///
/// List of possible UPnP errors:
/// 402 - Invalid Args
/// 714 - NoSuchEntryInArray (Port Mapping doesn't exist)
///
[DllImport("miniupnp.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int UPNP_DeletePortMapping([In] String controlURL,
[In] String serviceType,
[In] String externalPort,
[In] String protocol);
#region Utility Methods
public static UPNPDev PtrToUPNPDev(IntPtr devlistP)
{
return (UPNPDev)Marshal.PtrToStructure(devlistP, typeof(UPNPDev));
}
public static String NullTerminatedArrayToString(byte[] nullTerminatedStr)
{
for (int i = 0; i < nullTerminatedStr.Length; i++)
{
if (nullTerminatedStr[i] == 0)
{
return System.Text.Encoding.ASCII.GetString(nullTerminatedStr, 0, i);
}
}
return System.Text.Encoding.ASCII.GetString(nullTerminatedStr, 0, nullTerminatedStr.Length);
}
#endregion
}
}