ela-compil / BACnet

BACnet protocol library for .NET :satellite:
https://www.nuget.org/packages/bacnet/
MIT License
217 stars 96 forks source link

Raspberry Pi Example Has Exception - Platform not supported #44

Open JawadJaber opened 5 years ago

JawadJaber commented 5 years ago

I tried to run the RP example with Mono, and with .Net Core 2.2 Both trials return similar message at this line

bacnet_client.Start();

platform not supported exception socket.iocontrol, handles Windows-specific control codes and is not supported on this platform.

hoangdungt2 commented 5 years ago

for my case, it works just fine, when you create bacnet client do not enter ip address in there var bacnetClient = new BacnetClient(new BacnetIpUdpProtocolTransport(0xBAC0, false)); bacnetClient.start(); I don't use mono, just publish as "linux-arm" and it will work well for rp3, e.g. dotnet publish -c Release -r linux-arm -o outputFolder

pnguyen-ecs commented 5 years ago

I'm getting the same exception with the same calls as hoangdungt2 on a OSX and Linux Debian. I'm using an ARM processor. The error seems to stem from the following line in the BACnet.dll

client?.Client.IOControl(unchecked((int)SIO_UDP_CONNRESET),
                new[] { System.Convert.ToByte(false) }, null);
mykah89 commented 5 years ago

I fixed this in my fork awhile ago, sorry for being vague since i dont completely remember, but the best i could gather when i looked into it was that the conn reset was a windows only thing. Hope it helps.

        /// <summary>
        ///   Done to prevent exceptions in Socket.BeginReceive()
        ///   May only be an issue on windows.
        /// </summary>
        /// <remarks>
        ///   http://microsoft.public.win32.programmer.networks.narkive.com/RlxW2V6m/udp-comms-and-connection-reset-problem
        ///   https://stackoverflow.com/questions/34242622/windows-udp-sockets-recvfrom-fails-with-error-10054
        ///   https://stackoverflow.com/questions/38790802/determine-operating-system-in-net-core
        /// </remarks>
        private static void DisableConnReset(UdpClient client)
        {
            if (EnvironmentHelper.IsWindowsEnvironment())
            {
                const uint IOC_IN = 0x80000000;
                const uint IOC_VENDOR = 0x18000000;
                const uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;

                client?.Client.IOControl(unchecked((int)SIO_UDP_CONNRESET),
                    new[] { System.Convert.ToByte(false) }, null);
            }
        }
pnguyen-ecs commented 5 years ago

I made the following change to BacnetIpUdpProtocolTransport.cs file of the v2-netstandard branch

line 85 if (_dontFragment) _sharedConn.DontFragment = _dontFragment;

removed line 105

added line 107 if (_dontFragment) _exclusiveConn.DontFragment = _dontFragment;

changed line 139 to

            try
            {
                client?.Client.IOControl(unchecked((int)SIO_UDP_CONNRESET),
                    new[] { System.Convert.ToByte(false) }, null);
            }
            catch (PlatformNotSupportedException ex)
            {
                var socket = new Socket(client.Client.AddressFamily, client.Client.SocketType, client.Client.ProtocolType);
                socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
            }

Note: This will only work if you call BacnetIpUdpProtocolTransport() with dontFragment=false. I don't know much about socket programming but I assume that disabling connection reset is the same as keeping the connection alive.

JawadJaber commented 5 years ago

The solution provided by @mykah89 and @pnguyen-ecs worked for me and no errors appeared. Many thanks everybody.🙏

minzdrav commented 4 years ago

Hi BACnet libary team Please reopen issue and integrate fix for DisableConnReset to v2-netstandard branch. I'm using .net core 3.1. Library working fine on windows 10 + wsl2 + docker and on raspberry pi 4 + ubuntu + docker. IsOSPlatform is supported by .net core, .net framework, .net standard https://docs.microsoft.com/en-US/dotnet/api/system.runtime.interopservices.runtimeinformation.isosplatform?view=netcore-3.1

        private static void DisableConnReset(UdpClient client)
        {
            bool isWindows = System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
            if (isWindows)
            {
                const uint IOC_IN = 0x80000000;
                const uint IOC_VENDOR = 0x18000000;
                const uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;

                client?.Client.IOControl(unchecked((int)SIO_UDP_CONNRESET),
                    new[] { System.Convert.ToByte(false) }, null);
            }
        }
gralin commented 4 years ago

Hi @minzdrav, you are right this should be integrated with that branch. I will let you know when this is available.

Sn3b commented 4 years ago

Any idea when this change will be available?