Universal Plug & Play describes devices that work with a computer system as soon as they are connected. UPnP is an extension of this idea that expands the range of Plug and Play devices to networking equipment. Universal Plug and Play uses network protocols to allow a wide range of devices to be interconnected and work seamlessly with each other. [1]

Since most UPnP devices support zero-configuration setup (like ordinary Plug and Play devices), it is simple to add devices to a network and use them immediately. [1]

There are several good implementations of UPNP in C#. However the most ease-to-use (according to my opinion) is Open.NAT [2]. The following source code encapsulates the Open.NAT library API to a simpler API.

    public class Upnp
    {
        public I_Status statusInitialized;     
        private NatDevice device;
        private NatDiscoverer discoverer;
        private CancellationTokenSource cts;
        private List<Tuple<int, int, string>> mappedPorts;

        public Upnp()
        {
            statusInitialized = I_Status.Unknown;
            mappedPorts = new List<Tuple<int,int,string>>();
        }

        public I_Status Initialize(bool blocking)
        {
            AutoResetEvent mWaitForThread = new AutoResetEvent(false);

            Thread thread = new Thread(async () =>
            {
                try
                {
                    discoverer = new NatDiscoverer();
                    cts = new CancellationTokenSource(20000);
                    device = await discoverer.DiscoverDeviceAsync(PortMapper.Upnp, cts);
                }
                catch (Exception)
                {
                    statusInitialized = I_Status.Error;
                    mWaitForThread.Set();
                    Thread.CurrentThread.Abort();
                }
                statusInitialized = I_Status.OK;
                mWaitForThread.Set();
                Thread.CurrentThread.Abort();
            });

            thread.Start();

            if (blocking == true)
                mWaitForThread.WaitOne();

            return blocking == true ? statusInitialized : I_Status.OK;
        }

        public I_Status CreatePortMapping(int prvPort,int pubPort, Open.Nat.Protocol protocol, string name)
        {
            I_Status retVal = I_Status.OK;

            AutoResetEvent mWaitForThread = new AutoResetEvent(false);

            if (statusInitialized != I_Status.OK)
                return I_Status.Error;

            Thread thread = new Thread(async () =>
            {
                try
                {
                    var list = await device.GetAllMappingsAsync();

                    foreach (var x in list)
                        if (x.PrivatePort == prvPort)
                            await device.DeletePortMapAsync(x);

                    await device.CreatePortMapAsync(new Mapping(protocol, prvPort, pubPort, name));

                    mWaitForThread.Set();
                    Thread.CurrentThread.Abort();
                }
                catch (Exception)
                {
                    retVal =  I_Status.Error;
                    mWaitForThread.Set();
                    Thread.CurrentThread.Abort();
                }
            });

            thread.Start();
            mWaitForThread.WaitOne();

            return retVal;
        }

        public I_Status DeleteMappedPorts()
        {
            I_Status retVal = I_Status.OK;

            AutoResetEvent mWaitForThread = new AutoResetEvent(false);

            if (statusInitialized != I_Status.OK)
                return I_Status.Error;

            Thread thread = new Thread(async () =>
            {
                try
                {
                    foreach (var k in mappedPorts)
                    {
                        var list = await device.GetAllMappingsAsync();
                        foreach (var x in list)
                            if (x.PrivatePort == k.Item1)
                                await device.DeletePortMapAsync(x);
                        Thread.Sleep(5);
                    }
                    mWaitForThread.Set();
                    Thread.CurrentThread.Abort();
                }
                catch (Exception)
                {
                    retVal = I_Status.Error;
                    mWaitForThread.Set();
                    Thread.CurrentThread.Abort();
                }
            });

            thread.Start();
            mWaitForThread.WaitOne();

            return retVal;
        }
    }

 

NOTICE: Universal Plug and Play (UPnP) is one technological advancement that, too, comes with its share of drawbacks. It’s a technology of convenience but that convenience can leave your system vulnerable to certain problems if you don’t keep an eye on it.

References:

  1. https://techterms.com/definition/upnp
  2. https://github.com/lontivero/Open.NAT

 

Author

Write A Comment