-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcan-socket.cpp
102 lines (79 loc) · 2.43 KB
/
can-socket.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include "can-socket.h"
#include "posix-error-check.h"
#include <net/if.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <cstring>
can_socket_t::can_socket_t()
: fd_(check_error(::socket(PF_CAN, SOCK_RAW, CAN_RAW), "socket"))
{}
can_socket_t::~can_socket_t()
{
::close(fd_);
}
int can_socket_t::native() const
{
return fd_;
}
void can_socket_t::bind(const endpoint_t &endpoint)
{
sockaddr_can addr = get_sockaddr(endpoint);
int rc = ::bind(fd_, (const sockaddr*)&addr, sizeof(addr));
check_error(rc, "bind");
}
size_t can_socket_t::recv(void *buffer, size_t len)
{
struct can_frame frame;
ssize_t bytes = ::recv(fd_, &frame, sizeof(frame), 0);
check_error(bytes, "recv");
constexpr size_t can_header_len = sizeof(frame) - CAN_MAX_DLEN;
// short header
if (bytes <= can_header_len) {
return 0;
}
// short body
if (bytes < frame.can_dlc + can_header_len) {
return 0;
}
std::memcpy(buffer, frame.data, frame.can_dlc);
return static_cast<size_t>(frame.can_dlc);
}
size_t can_socket_t::sendto(const endpoint_t &endpoint, const void *buffer, size_t len)
{
if (len > CAN_MAX_DLEN) {
throw std::out_of_range("buffer is too long");
}
struct can_frame frame{};
frame.can_id = 1;
frame.can_dlc = len;
std::memcpy(&frame.data, buffer, len);
sockaddr_can addr = get_sockaddr(endpoint);
ssize_t written = ::sendto(fd_, &frame, sizeof(frame), 0, (const sockaddr*)&addr, sizeof(addr));
check_error(written, "sendto");
return static_cast<size_t>(written);
}
void can_socket_t::set_option(const socket_option_t &opt)
{
const auto &value = opt.value();
int rc = ::setsockopt(fd_, opt.level(), opt.name(), value.data(), value.size());
check_error(rc, "setsockopt");
}
sockaddr_can can_socket_t::get_sockaddr(const endpoint_t &endpoint)
{
const auto &can_endpoint = endpoint_cast(endpoint);
struct ifreq ifr;
std::strcpy(ifr.ifr_name, can_endpoint.device());
int rc = ioctl(fd_, SIOCGIFINDEX, &ifr);
check_error(rc, "ioctl");
sockaddr_can addr{};
addr.can_family = can_endpoint.family();
addr.can_ifindex = ifr.ifr_ifindex;
return addr;
}
const can_endpoint_t& can_socket_t::endpoint_cast(const endpoint_t &endpoint)
{
if (endpoint.family() != AF_CAN) {
throw std::system_error(EAFNOSUPPORT, std::generic_category());
}
return static_cast<const can_endpoint_t&>(endpoint);
}