derek-will / SocketCANSharp

.NET managed wrapper for SocketCAN on Linux
BSD 3-Clause "New" or "Revised" License
54 stars 13 forks source link

SocketCANSharp.Network.SocketCanException (100): Network is down #85

Closed JaggerJo closed 3 weeks ago

JaggerJo commented 2 months ago

Thanks for maintaining modern bindings to socket can!

We are encountering issues when we use socket can early during system initialisation.

When we call var numBytes = _rawCanSocket.Read(out CanFrame frame) the following exception is thrown.

SocketCANSharp.Network.SocketCanException (100): Network is down

While looking at the sources of Read I can't find the source of the "Network is down" exception.

https://github.com/derek-will/SocketCANSharp/blob/a5410e4402cedfb2cbd6bf33304f1e539e133816/src/SocketCANSharp/Network/RawCanSocket.cs#L265-L276

(We know why we get it, our process starts as a service before the can network interface is properly initialised. But we'd like to gracefully handle it and just start can communication whenever it's ready)

SocketCanSharp: 0.11.0 dotnet: 8.0.400

derek-will commented 1 month ago

"Network is down" in the Message property of the SocketCanException which is thrown is actually from the base class which is SocketException. When I throw the SocketCanException with the Description property set to "Reading from the underlying CAN_RAW socket failed." the base class automatically captures the errno corresponding to the previous write call on the socket which failed. The exception also automatically generates a useful message corresponding to that errno. In this instance, the issue is the fact that the interface is still not yet up and running.

You can easily check and wait on the status of the CAN Network Interface using SocketCAN#. Here is an example:

IEnumerable<CanNetworkInterface> collection = CanNetworkInterface.GetAllInterfaces(false);
CanNetworkInterface iface = collection.FirstOrDefault(i => i.Name.Equals("can0"));

Console.WriteLine("Waiting for CAN Interface to be up...");
do
{
    System.Threading.Thread.Sleep(1000);
} while (iface.OperationalStatus == InterfaceOperationalStatus.IF_OPER_DOWN);
// For physical interfaces this will return IF_OPER_UP and for 
// virtual interfaces this will return IF_OPER_UNKNOWN when the interface is ready

The specifics will of course depend on how your software is designed, but you basically just need to poll the OperationalStatus property of the CanNetworkInterface instance you are working with until it signals that it is ready.