blob: 7a647cc4b73665696d2471c644629c3d20119d3f [file] [log] [blame]
Vernon Mauery9e801a22018-10-12 13:20:49 -07001#include "sd_event_loop.hpp"
2
3#include "main.hpp"
4#include "message_handler.hpp"
5
Dave Cobbley2c15f0c2017-11-13 16:19:09 -08006#include <netinet/in.h>
Tom Joseph7fd26dd2017-03-14 15:26:26 +05307#include <sys/ioctl.h>
Dave Cobbley2c15f0c2017-11-13 16:19:09 -08008#include <sys/socket.h>
Tom Joseph7fd26dd2017-03-14 15:26:26 +05309#include <systemd/sd-daemon.h>
Vernon Mauery9e801a22018-10-12 13:20:49 -070010
Vernon Mauerycbccb052018-10-24 13:52:22 -070011#include <boost/asio/io_context.hpp>
Tom Joseph7fd26dd2017-03-14 15:26:26 +053012#include <phosphor-logging/log.hpp>
Vernon Mauerycbccb052018-10-24 13:52:22 -070013#include <sdbusplus/asio/sd_event.hpp>
Tom Joseph7fd26dd2017-03-14 15:26:26 +053014
15namespace eventloop
16{
17using namespace phosphor::logging;
18
Vernon Mauery7a0142c2018-11-09 08:38:16 -080019void EventLoop::handleRmcpPacket()
Tom Joseph7fd26dd2017-03-14 15:26:26 +053020{
Tom Joseph7fd26dd2017-03-14 15:26:26 +053021 try
22 {
Vernon Mauery7a0142c2018-11-09 08:38:16 -080023 auto channelPtr = std::make_shared<udpsocket::Channel>(udpSocket);
Tom Joseph7fd26dd2017-03-14 15:26:26 +053024
25 // Initialize the Message Handler with the socket channel
Vernon Mauery8d6f2002018-11-07 09:55:53 -080026 auto msgHandler = std::make_shared<message::Handler>(channelPtr, io);
Tom Joseph7fd26dd2017-03-14 15:26:26 +053027
Vernon Mauery8d6f2002018-11-07 09:55:53 -080028 msgHandler->processIncoming();
Tom Joseph7fd26dd2017-03-14 15:26:26 +053029 }
Vernon Mauery7a0142c2018-11-09 08:38:16 -080030 catch (const std::exception& e)
Tom Joseph7fd26dd2017-03-14 15:26:26 +053031 {
Vernon Mauery7a0142c2018-11-09 08:38:16 -080032 log<level::ERR>("Executing the IPMI message failed",
33 entry("EXCEPTION=%s", e.what()));
Tom Joseph7fd26dd2017-03-14 15:26:26 +053034 }
Vernon Mauery7a0142c2018-11-09 08:38:16 -080035}
Tom Joseph7fd26dd2017-03-14 15:26:26 +053036
Vernon Mauery7a0142c2018-11-09 08:38:16 -080037void EventLoop::startRmcpReceive()
38{
39 udpSocket->async_wait(boost::asio::socket_base::wait_read,
40 [this](const boost::system::error_code& ec) {
41 if (!ec)
42 {
43 io->post([this]() { startRmcpReceive(); });
44 handleRmcpPacket();
45 }
46 });
Tom Joseph7fd26dd2017-03-14 15:26:26 +053047}
48
Vernon Maueryd92bc322019-03-15 15:24:30 -070049int EventLoop::setupSocket(std::shared_ptr<sdbusplus::asio::connection>& bus,
50 std::string iface, uint16_t reqPort)
51{
52 static constexpr const char* unboundIface = "rmcpp";
53 if (iface == "")
54 {
55 iface = unboundIface;
56 }
57 // Create our own socket if SysD did not supply one.
58 int listensFdCount = sd_listen_fds(0);
59 if (listensFdCount > 1)
60 {
61 log<level::ERR>("Too many file descriptors received");
62 return EXIT_FAILURE;
63 }
64 if (listensFdCount == 1)
65 {
66 int openFd = SD_LISTEN_FDS_START;
67 if (!sd_is_socket(openFd, AF_UNSPEC, SOCK_DGRAM, -1))
68 {
69 log<level::ERR>("Failed to set up systemd-passed socket");
70 return EXIT_FAILURE;
71 }
72 udpSocket = std::make_shared<boost::asio::ip::udp::socket>(
73 *io, boost::asio::ip::udp::v6(), openFd);
74 }
75 else
76 {
77 // asio does not natively offer a way to bind to an interface
78 // so it must be done in steps
79 boost::asio::ip::udp::endpoint ep(boost::asio::ip::udp::v6(), reqPort);
80 udpSocket = std::make_shared<boost::asio::ip::udp::socket>(*io);
81 udpSocket->open(ep.protocol());
82 // bind
83 udpSocket->set_option(
84 boost::asio::ip::udp::socket::reuse_address(true));
85 udpSocket->bind(ep);
86 }
87 // SO_BINDTODEVICE
88 char nameout[IFNAMSIZ];
89 unsigned int lenout = sizeof(nameout);
90 if ((::getsockopt(udpSocket->native_handle(), SOL_SOCKET, SO_BINDTODEVICE,
91 nameout, &lenout) == -1))
92 {
93 log<level::ERR>("Failed to read bound device",
94 entry("ERROR=%s", strerror(errno)));
95 }
96 if (iface != nameout && iface != unboundIface)
97 {
98 // SO_BINDTODEVICE
99 if ((::setsockopt(udpSocket->native_handle(), SOL_SOCKET,
100 SO_BINDTODEVICE, iface.c_str(),
101 iface.size() + 1) == -1))
102 {
103 log<level::ERR>("Failed to bind to requested interface",
104 entry("ERROR=%s", strerror(errno)));
105 return EXIT_FAILURE;
106 }
107 }
108 // cannot be constexpr because it gets passed by address
109 const int option_enabled = 1;
110 // common socket stuff; set options to get packet info (DST addr)
111 ::setsockopt(udpSocket->native_handle(), IPPROTO_IP, IP_PKTINFO,
112 &option_enabled, sizeof(option_enabled));
113 ::setsockopt(udpSocket->native_handle(), IPPROTO_IPV6, IPV6_RECVPKTINFO,
114 &option_enabled, sizeof(option_enabled));
115
116 // set the dbus name
117 std::string busName = "xyz.openbmc_project.Ipmi.Channel." + iface;
118 try
119 {
120 bus->request_name(busName.c_str());
121 }
122 catch (const std::exception& e)
123 {
124 log<level::ERR>("Failed to acquire D-Bus name",
125 entry("NAME=%s", busName.c_str()),
126 entry("ERROR=%s", e.what()));
127 return EXIT_FAILURE;
128 }
129 return 0;
130}
131
Vernon Mauerycbccb052018-10-24 13:52:22 -0700132int EventLoop::startEventLoop()
Tom Joseph7fd26dd2017-03-14 15:26:26 +0530133{
Vernon Mauery22c8a212018-10-24 14:51:23 -0700134 // set up boost::asio signal handling
135 boost::asio::signal_set signals(*io, SIGINT, SIGTERM);
Vernon Mauery7a0142c2018-11-09 08:38:16 -0800136 signals.async_wait(
137 [this](const boost::system::error_code& error, int signalNumber) {
138 udpSocket->cancel();
139 udpSocket->close();
140 io->stop();
141 });
Tom Joseph7fd26dd2017-03-14 15:26:26 +0530142
Vernon Mauery7a0142c2018-11-09 08:38:16 -0800143 startRmcpReceive();
Tom Joseph7fd26dd2017-03-14 15:26:26 +0530144
Vernon Mauerycbccb052018-10-24 13:52:22 -0700145 io->run();
Tom Joseph7fd26dd2017-03-14 15:26:26 +0530146
Vernon Mauerycbccb052018-10-24 13:52:22 -0700147 return EXIT_SUCCESS;
Tom Joseph7fd26dd2017-03-14 15:26:26 +0530148}
149
Tom Joseph7fd26dd2017-03-14 15:26:26 +0530150} // namespace eventloop