mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-10-28 13:33:40 +08:00
SocketCAN: Proper error reporting from openSocket()
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
|
#include <cstring>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace uavcan_linux
|
namespace uavcan_linux
|
||||||
@@ -16,9 +17,14 @@ class Exception : public std::runtime_error
|
|||||||
{
|
{
|
||||||
const int errno_;
|
const int errno_;
|
||||||
|
|
||||||
|
static std::string makeErrorString(const std::string& descr)
|
||||||
|
{
|
||||||
|
return descr + " [errno " + std::to_string(errno) + " \"" + std::strerror(errno) + "\"]";
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Exception(const std::string& descr)
|
explicit Exception(const std::string& descr)
|
||||||
: std::runtime_error(descr)
|
: std::runtime_error(makeErrorString(descr))
|
||||||
, errno_(errno)
|
, errno_(errno)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|||||||
@@ -381,6 +381,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual ~SocketCanIface()
|
virtual ~SocketCanIface()
|
||||||
{
|
{
|
||||||
|
UAVCAN_TRACE("SocketCAN", "SocketCanIface: Closing fd %d", fd_);
|
||||||
(void)::close(fd_);
|
(void)::close(fd_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -515,68 +516,91 @@ public:
|
|||||||
*/
|
*/
|
||||||
static int openSocket(const std::string& iface_name)
|
static int openSocket(const std::string& iface_name)
|
||||||
{
|
{
|
||||||
|
errno = 0;
|
||||||
|
|
||||||
const int s = ::socket(PF_CAN, SOCK_RAW, CAN_RAW);
|
const int s = ::socket(PF_CAN, SOCK_RAW, CAN_RAW);
|
||||||
if (s < 0)
|
if (s < 0)
|
||||||
{
|
{
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class RaiiCloser
|
||||||
|
{
|
||||||
|
int fd_;
|
||||||
|
public:
|
||||||
|
RaiiCloser(int filedesc) : fd_(filedesc)
|
||||||
|
{
|
||||||
|
assert(fd_ >= 0);
|
||||||
|
}
|
||||||
|
~RaiiCloser()
|
||||||
|
{
|
||||||
|
if (fd_ >= 0)
|
||||||
|
{
|
||||||
|
UAVCAN_TRACE("SocketCAN", "RaiiCloser: Closing fd %d", fd_);
|
||||||
|
(void)::close(fd_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void disarm() { fd_ = -1; }
|
||||||
|
} raii_closer(s);
|
||||||
|
|
||||||
// Detect the iface index
|
// Detect the iface index
|
||||||
auto ifr = ::ifreq();
|
auto ifr = ::ifreq();
|
||||||
if (iface_name.length() >= IFNAMSIZ)
|
if (iface_name.length() >= IFNAMSIZ)
|
||||||
{
|
{
|
||||||
goto fail;
|
errno = ENAMETOOLONG;
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
(void)std::strncpy(ifr.ifr_name, iface_name.c_str(), iface_name.length());
|
(void)std::strncpy(ifr.ifr_name, iface_name.c_str(), iface_name.length());
|
||||||
if (::ioctl(s, SIOCGIFINDEX, &ifr) < 0 || ifr.ifr_ifindex < 0)
|
if (::ioctl(s, SIOCGIFINDEX, &ifr) < 0 || ifr.ifr_ifindex < 0)
|
||||||
{
|
{
|
||||||
goto fail;
|
return -1;
|
||||||
}
|
}
|
||||||
// Bind to a CAN iface
|
|
||||||
|
// Bind to the specified CAN iface
|
||||||
{
|
{
|
||||||
auto addr = ::sockaddr_can();
|
auto addr = ::sockaddr_can();
|
||||||
addr.can_family = AF_CAN;
|
addr.can_family = AF_CAN;
|
||||||
addr.can_ifindex = ifr.ifr_ifindex;
|
addr.can_ifindex = ifr.ifr_ifindex;
|
||||||
if (::bind(s, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0)
|
if (::bind(s, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0)
|
||||||
{
|
{
|
||||||
goto fail;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure
|
// Configure
|
||||||
{
|
{
|
||||||
const int on = 1;
|
const int on = 1;
|
||||||
// Timestamping
|
// Timestamping
|
||||||
if (::setsockopt(s, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)) < 0)
|
if (::setsockopt(s, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)) < 0)
|
||||||
{
|
{
|
||||||
goto fail;
|
return -1;
|
||||||
}
|
}
|
||||||
// Socket loopback
|
// Socket loopback
|
||||||
if (::setsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, &on, sizeof(on)) < 0)
|
if (::setsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, &on, sizeof(on)) < 0)
|
||||||
{
|
{
|
||||||
goto fail;
|
return -1;
|
||||||
}
|
}
|
||||||
// Non-blocking
|
// Non-blocking
|
||||||
if (::fcntl(s, F_SETFL, O_NONBLOCK) < 0)
|
if (::fcntl(s, F_SETFL, O_NONBLOCK) < 0)
|
||||||
{
|
{
|
||||||
goto fail;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate the resulting socket
|
// Validate the resulting socket
|
||||||
{
|
{
|
||||||
int error = 0;
|
int socket_error = 0;
|
||||||
::socklen_t errlen = sizeof(error);
|
::socklen_t errlen = sizeof(socket_error);
|
||||||
(void)::getsockopt(s, SOL_SOCKET, SO_ERROR, reinterpret_cast<void*>(&error), &errlen);
|
(void)::getsockopt(s, SOL_SOCKET, SO_ERROR, reinterpret_cast<void*>(&socket_error), &errlen);
|
||||||
if (error != 0)
|
if (socket_error != 0)
|
||||||
{
|
{
|
||||||
goto fail;
|
errno = socket_error;
|
||||||
UAVCAN_TRACE("SocketCAN", "Socket error: iface='%s' errno=%d error=%d",
|
return -1;
|
||||||
iface_name.c_str(), errno, error);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return s;
|
|
||||||
|
|
||||||
fail:
|
raii_closer.disarm();
|
||||||
(void)::close(s);
|
return s;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user