boost::asio over SocketCAN

boost, boost-asio, c++, can-bus, sockets

Solution

The solution is to use `posix::stream_descriptor`.

Just open the native socket, bind and then use `posix::basic_stream_descriptor::assign`.

Problem

I was thinking of making use of Boost Asio to read data from a Socket CAN. There's nothing fancy going on in linux/can.h , and the device should behave like the loopback interface, and be used with a raw socket. Looking at the `basic_raw_socket` interface it seems that I can make use of basic_raw_socket::assign to assign the native socket created with ``` socket( PF_CAN, SOCK_RAW, CAN_RAW ); ``` This is what I have so far ``` namespace can { class CanSocket { public: typedef boost::asio::ip::basic_endpoint<CanSocket> endpoint; typedef boost::asio::ip::basic_resolver_query<CanSocket> resolver_query; typedef boost::asio::ip::basic_resolver_iterator<CanSocket> resolver_iterator; typedef boost::asio::basic_raw_socket<CanSocket> socket; typedef boost::asio::ip::basic_resolver<CanSocket> resolver; CanSocket() : _protocol( CAN_RAW ) , _family( PF_CAN ) { } static CanSocket v4() { return CanSocket(); } static CanSocket v6(); int type() const; int protocol() const; int family() const; friend bool operator==(const CanSocket& p1, const CanSocket& p2) { return p1._protocol != p2._protocol || p1._family != p2._family; } friend bool operator!=(const CanSocket& p1, const CanSocket& p2) { return p1._protocol == p2._protocol || p1._family == p2._family; } private: int _protocol; int _family; }; } ``` And this is how I use it in my application ``` boost::asio::io_service ioserv; CanSocket::socket s( ioserv ); int sock = socket( PF_CAN, SOCK_RAW, CAN_RAW ); s.assign(CanSocket::v4(), sock); struct ifreq ifr; strcpy(ifr.ifr_name, "vcan0"); ioctl(sock, SIOCGIFINDEX, &ifr); /* ifr.ifr_ifindex gets filled * with that device's index */ /* Select that CAN interface, and bind the socket to it. */ /* this should be the endpoint */ struct sockaddr_can addr; addr.can_family = AF_CAN; addr.can_ifindex = ifr.ifr_ifindex; /* s.bind (....) */ bind( sock, (struct sockaddr*)&addr, sizeof(addr) ); ``` What I don't quite get is how do I bind `s` to the local endpoint? There are no IPs or ports involved. Is there anything else that should be implemented besides the endpoint to get it going?

Original source