xref: /openbmc/sdbusplus/include/sdbusplus/asio/connection.hpp (revision 17a3263c344ef3be3967ec1ddfe27ae4c2b5db4e)
17f664254SPatrick Williams /*
27f664254SPatrick Williams // Copyright (c) 2018 Intel Corporation
37f664254SPatrick Williams //
47f664254SPatrick Williams // Licensed under the Apache License, Version 2.0 (the "License");
57f664254SPatrick Williams // you may not use this file except in compliance with the License.
67f664254SPatrick Williams // You may obtain a copy of the License at
77f664254SPatrick Williams //
87f664254SPatrick Williams //      http://www.apache.org/licenses/LICENSE-2.0
97f664254SPatrick Williams //
107f664254SPatrick Williams // Unless required by applicable law or agreed to in writing, software
117f664254SPatrick Williams // distributed under the License is distributed on an "AS IS" BASIS,
127f664254SPatrick Williams // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137f664254SPatrick Williams // See the License for the specific language governing permissions and
147f664254SPatrick Williams // limitations under the License.
157f664254SPatrick Williams */
167f664254SPatrick Williams #pragma once
177f664254SPatrick Williams 
187f664254SPatrick Williams #ifndef BOOST_COROUTINES_NO_DEPRECATION_WARNING
197f664254SPatrick Williams // users should define this if they directly include boost/asio/spawn.hpp,
207f664254SPatrick Williams // but by defining it here, warnings won't cause problems with a compile
217f664254SPatrick Williams #define BOOST_COROUTINES_NO_DEPRECATION_WARNING
227f664254SPatrick Williams #endif
237f664254SPatrick Williams 
2438ab5ecfSEd Tanous #include <boost/asio/async_result.hpp>
2538ab5ecfSEd Tanous #include <boost/asio/io_context.hpp>
2638ab5ecfSEd Tanous #include <boost/asio/posix/stream_descriptor.hpp>
2738ab5ecfSEd Tanous #include <boost/asio/post.hpp>
28cd3bf08aSEd Tanous #include <boost/asio/steady_timer.hpp>
29cd3bf08aSEd Tanous 
301778b12bSEd Tanous #ifndef SDBUSPLUS_DISABLE_BOOST_COROUTINES
317f664254SPatrick Williams #include <boost/asio/spawn.hpp>
321778b12bSEd Tanous #endif
337f664254SPatrick Williams #include <boost/callable_traits.hpp>
347f664254SPatrick Williams #include <sdbusplus/asio/detail/async_send_handler.hpp>
357f664254SPatrick Williams #include <sdbusplus/message.hpp>
367f664254SPatrick Williams #include <sdbusplus/utility/read_into_tuple.hpp>
377f664254SPatrick Williams #include <sdbusplus/utility/type_traits.hpp>
387f664254SPatrick Williams 
397f664254SPatrick Williams #include <chrono>
4067cfca77SAlexander Hansen #include <functional>
417f664254SPatrick Williams #include <string>
427f664254SPatrick Williams #include <tuple>
437f664254SPatrick Williams 
447f664254SPatrick Williams namespace sdbusplus
457f664254SPatrick Williams {
467f664254SPatrick Williams 
477f664254SPatrick Williams namespace asio
487f664254SPatrick Williams {
497f664254SPatrick Williams 
507f664254SPatrick Williams /// Root D-Bus IO object
517f664254SPatrick Williams /**
527f664254SPatrick Williams  * A connection to a bus, through which messages may be sent or received.
537f664254SPatrick Williams  */
540f282c48SPatrick Williams class connection : public sdbusplus::bus_t
557f664254SPatrick Williams {
567f664254SPatrick Williams   public:
57*17a3263cSPatrick Williams     // default to default bus
connection(boost::asio::io_context & io,sdbusplus::bus_t && bus=sdbusplus::bus::new_default ())58*17a3263cSPatrick Williams     explicit connection(
59*17a3263cSPatrick Williams         boost::asio::io_context& io,
60*17a3263cSPatrick Williams         sdbusplus::bus_t&& bus = sdbusplus::bus::new_default()) :
61*17a3263cSPatrick Williams         sdbusplus::bus_t(std::move(bus)), io_(io),
62cd3bf08aSEd Tanous         socket(io_.get_executor(), get_fd()), timer(io_.get_executor())
637f664254SPatrick Williams     {
64894d6ca4SRahul Kapoor         read_immediate();
657f664254SPatrick Williams     }
connection(boost::asio::io_context & io,sd_bus * bus)667f664254SPatrick Williams     connection(boost::asio::io_context& io, sd_bus* bus) :
67cd3bf08aSEd Tanous         sdbusplus::bus_t(bus), io_(io), socket(io_.get_executor(), get_fd()),
68cd3bf08aSEd Tanous         timer(io_.get_executor())
697f664254SPatrick Williams     {
70894d6ca4SRahul Kapoor         read_immediate();
717f664254SPatrick Williams     }
~connection()727f664254SPatrick Williams     ~connection()
737f664254SPatrick Williams     {
747f664254SPatrick Williams         // The FD will be closed by the socket object, so assign null to the
757f664254SPatrick Williams         // sd_bus object to avoid a double close()  Ignore return codes here,
767f664254SPatrick Williams         // because there's nothing we can do about errors
777f664254SPatrick Williams         socket.release();
787f664254SPatrick Williams     }
797f664254SPatrick Williams 
807f664254SPatrick Williams     /** @brief Perform an asynchronous send of a message, executing the handler
817f664254SPatrick Williams      *         upon return and return
827f664254SPatrick Williams      *
837f664254SPatrick Williams      *  @param[in] m - A message ready to send
846c97486fSEd Tanous      *  @param[in] token - The completion token to execute upon completion;
85ddc57bdfSEd Tanous      *  @param[in] timeout - The timeout in microseconds
867f664254SPatrick Williams      *
877f664254SPatrick Williams      */
8850fe983aSEd Tanous 
8950fe983aSEd Tanous     using callback_t = void(boost::system::error_code, message_t&);
9050fe983aSEd Tanous     using send_function = std::move_only_function<callback_t>;
async_send(message_t & m,send_function && callback,uint64_t timeout=0)9150fe983aSEd Tanous     inline void async_send(message_t& m, send_function&& callback,
926c97486fSEd Tanous                            uint64_t timeout = 0)
937f664254SPatrick Williams     {
9450fe983aSEd Tanous         boost::asio::async_initiate<send_function, callback_t>(
9550fe983aSEd Tanous             detail::async_send_handler(get(), m, timeout), callback);
9650fe983aSEd Tanous     }
9750fe983aSEd Tanous #ifndef SDBUSPLUS_DISABLE_BOOST_COROUTINES
async_send_yield(message_t & m,boost::asio::yield_context && token,uint64_t timeout=0)9850fe983aSEd Tanous     inline auto async_send_yield(message_t& m,
9950fe983aSEd Tanous                                  boost::asio::yield_context&& token,
10050fe983aSEd Tanous                                  uint64_t timeout = 0)
10150fe983aSEd Tanous     {
10250fe983aSEd Tanous         using yield_callback_t = void(boost::system::error_code, message_t);
10350fe983aSEd Tanous         return boost::asio::async_initiate<boost::asio::yield_context,
10450fe983aSEd Tanous                                            yield_callback_t>(
1056c97486fSEd Tanous             detail::async_send_handler(get(), m, timeout), token);
1067f664254SPatrick Williams     }
10750fe983aSEd Tanous #endif
1087f664254SPatrick Williams 
109668c56b0SEd Tanous     template <typename MessageHandler>
unpack(boost::system::error_code ec,message_t & r,MessageHandler && handler)110668c56b0SEd Tanous     static void unpack(boost::system::error_code ec, message_t& r,
111668c56b0SEd Tanous                        MessageHandler&& handler)
112668c56b0SEd Tanous     {
113668c56b0SEd Tanous         using FunctionTuple = boost::callable_traits::args_t<MessageHandler>;
114668c56b0SEd Tanous         using FunctionTupleType = utility::decay_tuple_t<FunctionTuple>;
115668c56b0SEd Tanous         constexpr bool returnWithMsg = []() {
116668c56b0SEd Tanous             if constexpr ((std::tuple_size_v<FunctionTupleType>) > 1)
117668c56b0SEd Tanous             {
118668c56b0SEd Tanous                 return std::is_same_v<
119668c56b0SEd Tanous                     std::tuple_element_t<1, FunctionTupleType>,
120668c56b0SEd Tanous                     sdbusplus::message_t>;
121668c56b0SEd Tanous             }
122668c56b0SEd Tanous             return false;
123668c56b0SEd Tanous         }();
124668c56b0SEd Tanous         using UnpackType = utility::strip_first_n_args_t<returnWithMsg ? 2 : 1,
125668c56b0SEd Tanous                                                          FunctionTupleType>;
126668c56b0SEd Tanous         UnpackType responseData;
127668c56b0SEd Tanous         if (!ec)
128668c56b0SEd Tanous         {
129668c56b0SEd Tanous             try
130668c56b0SEd Tanous             {
131668c56b0SEd Tanous                 utility::read_into_tuple(responseData, r);
132668c56b0SEd Tanous             }
133668c56b0SEd Tanous             catch (const std::exception&)
134668c56b0SEd Tanous             {
135668c56b0SEd Tanous                 // Set error code if not already set
136668c56b0SEd Tanous                 ec = boost::system::errc::make_error_code(
137668c56b0SEd Tanous                     boost::system::errc::invalid_argument);
138668c56b0SEd Tanous             }
139668c56b0SEd Tanous         }
140668c56b0SEd Tanous         // Note.  Callback is called whether or not the unpack was
141668c56b0SEd Tanous         // successful to allow the user to implement their own
142668c56b0SEd Tanous         // handling
143668c56b0SEd Tanous         if constexpr (returnWithMsg)
144668c56b0SEd Tanous         {
145668c56b0SEd Tanous             auto response =
146668c56b0SEd Tanous                 std::tuple_cat(std::make_tuple(ec), std::forward_as_tuple(r),
147668c56b0SEd Tanous                                std::move(responseData));
148668c56b0SEd Tanous             std::apply(handler, response);
149668c56b0SEd Tanous         }
150668c56b0SEd Tanous         else
151668c56b0SEd Tanous         {
152668c56b0SEd Tanous             auto response =
153668c56b0SEd Tanous                 std::tuple_cat(std::make_tuple(ec), std::move(responseData));
154668c56b0SEd Tanous             std::apply(handler, response);
155668c56b0SEd Tanous         }
156668c56b0SEd Tanous     }
157668c56b0SEd Tanous 
1587f664254SPatrick Williams     /** @brief Perform an asynchronous method call, with input parameter packing
159da0b3f13SKonrad Sztyber      *         and return value unpacking.
1607f664254SPatrick Williams      *
1617f664254SPatrick Williams      *  @param[in] handler - A function object that is to be called as a
1627f664254SPatrick Williams      *                       continuation for the async dbus method call. The
1637f664254SPatrick Williams      *                       arguments to parse on the return are deduced from
1647f664254SPatrick Williams      *                       the handler's signature and then passed in along
16510d7aa12SPatrick Williams      *                       with an error code and optional message_t
1667f664254SPatrick Williams      *  @param[in] service - The service to call.
1677f664254SPatrick Williams      *  @param[in] objpath - The object's path for the call.
1687f664254SPatrick Williams      *  @param[in] interf - The object's interface to call.
1697f664254SPatrick Williams      *  @param[in] method - The object's method to call.
170da0b3f13SKonrad Sztyber      *  @param[in] timeout - The timeout for the method call in usec (0 results
171da0b3f13SKonrad Sztyber      *                       in using the default value).
172ddc57bdfSEd Tanous      *  @param[in] a - Optional parameters for the method call.
1737f664254SPatrick Williams      *
1747f664254SPatrick Williams      */
1757f664254SPatrick Williams     template <typename MessageHandler, typename... InputArgs>
async_method_call_timed(MessageHandler && handler,const std::string & service,const std::string & objpath,const std::string & interf,const std::string & method,uint64_t timeout,const InputArgs &...a)17606f265f6SPatrick Williams     void async_method_call_timed(
17706f265f6SPatrick Williams         MessageHandler&& handler, const std::string& service,
17806f265f6SPatrick Williams         const std::string& objpath, const std::string& interf,
17906f265f6SPatrick Williams         const std::string& method, uint64_t timeout, const InputArgs&... a)
1807f664254SPatrick Williams     {
181668c56b0SEd Tanous         using callback_t = std::move_only_function<void(
182668c56b0SEd Tanous             boost::system::error_code, message_t&)>;
183668c56b0SEd Tanous         callback_t applyHandler =
18406f265f6SPatrick Williams             [handler = std::forward<MessageHandler>(
18506f265f6SPatrick Williams                  handler)](boost::system::error_code ec, message_t& r) mutable {
186668c56b0SEd Tanous                 unpack(ec, r, std::move(handler));
1877f664254SPatrick Williams             };
18810d7aa12SPatrick Williams         message_t m;
1897f664254SPatrick Williams         boost::system::error_code ec;
1907f664254SPatrick Williams         try
1917f664254SPatrick Williams         {
1927f664254SPatrick Williams             m = new_method_call(service.c_str(), objpath.c_str(),
1937f664254SPatrick Williams                                 interf.c_str(), method.c_str());
1947f664254SPatrick Williams             m.append(a...);
1957f664254SPatrick Williams         }
1967f664254SPatrick Williams         catch (const exception::SdBusError& e)
1977f664254SPatrick Williams         {
1987f664254SPatrick Williams             ec = boost::system::errc::make_error_code(
1997f664254SPatrick Williams                 static_cast<boost::system::errc::errc_t>(e.get_errno()));
2007f664254SPatrick Williams             applyHandler(ec, m);
2017f664254SPatrick Williams             return;
2027f664254SPatrick Williams         }
203668c56b0SEd Tanous         async_send(m, std::move(applyHandler), timeout);
204da0b3f13SKonrad Sztyber     }
205da0b3f13SKonrad Sztyber 
206da0b3f13SKonrad Sztyber     /** @brief Perform an asynchronous method call, with input parameter packing
207da0b3f13SKonrad Sztyber      *         and return value unpacking. Uses the default timeout value.
208da0b3f13SKonrad Sztyber      *
209da0b3f13SKonrad Sztyber      *  @param[in] handler - A function object that is to be called as a
210da0b3f13SKonrad Sztyber      *                       continuation for the async dbus method call. The
211da0b3f13SKonrad Sztyber      *                       arguments to parse on the return are deduced from
212da0b3f13SKonrad Sztyber      *                       the handler's signature and then passed in along
21310d7aa12SPatrick Williams      *                       with an error code and optional message_t
214da0b3f13SKonrad Sztyber      *  @param[in] service - The service to call.
215da0b3f13SKonrad Sztyber      *  @param[in] objpath - The object's path for the call.
216da0b3f13SKonrad Sztyber      *  @param[in] interf - The object's interface to call.
217da0b3f13SKonrad Sztyber      *  @param[in] method - The object's method to call.
218ddc57bdfSEd Tanous      *  @param[in] a - Optional parameters for the method call.
219da0b3f13SKonrad Sztyber      *
220da0b3f13SKonrad Sztyber      */
221da0b3f13SKonrad Sztyber     template <typename MessageHandler, typename... InputArgs>
async_method_call(MessageHandler && handler,const std::string & service,const std::string & objpath,const std::string & interf,const std::string & method,InputArgs &&...a)222da0b3f13SKonrad Sztyber     void async_method_call(MessageHandler&& handler, const std::string& service,
223da0b3f13SKonrad Sztyber                            const std::string& objpath,
224da0b3f13SKonrad Sztyber                            const std::string& interf, const std::string& method,
2255a6a9141SEd Tanous                            InputArgs&&... a)
226da0b3f13SKonrad Sztyber     {
227da0b3f13SKonrad Sztyber         async_method_call_timed(std::forward<MessageHandler>(handler), service,
2285a6a9141SEd Tanous                                 objpath, interf, method, 0,
2295a6a9141SEd Tanous                                 std::forward<InputArgs>(a)...);
2307f664254SPatrick Williams     }
2317f664254SPatrick Williams 
2321778b12bSEd Tanous #ifndef SDBUSPLUS_DISABLE_BOOST_COROUTINES
233dfbd9ddfSLei YU     template <typename... RetTypes>
default_ret_types()234dfbd9ddfSLei YU     auto default_ret_types()
235dfbd9ddfSLei YU     {
236dfbd9ddfSLei YU         if constexpr (sizeof...(RetTypes) == 0)
237dfbd9ddfSLei YU         {
238dfbd9ddfSLei YU             return;
239dfbd9ddfSLei YU         }
240dfbd9ddfSLei YU         else if constexpr (sizeof...(RetTypes) == 1 &&
241dfbd9ddfSLei YU                            std::is_void_v<std::tuple_element_t<
242dfbd9ddfSLei YU                                0, std::tuple<RetTypes...>>>)
243dfbd9ddfSLei YU         {
244dfbd9ddfSLei YU             return;
245dfbd9ddfSLei YU         }
246dfbd9ddfSLei YU         else if constexpr (sizeof...(RetTypes) == 1)
247dfbd9ddfSLei YU         {
248dfbd9ddfSLei YU             return std::tuple_element_t<0, std::tuple<RetTypes...>>{};
249dfbd9ddfSLei YU         }
250dfbd9ddfSLei YU         else
251dfbd9ddfSLei YU         {
252dfbd9ddfSLei YU             return std::tuple<RetTypes...>{};
253dfbd9ddfSLei YU         }
254dfbd9ddfSLei YU     }
2557f664254SPatrick Williams     /** @brief Perform a yielding asynchronous method call, with input
2567f664254SPatrick Williams      *         parameter packing and return value unpacking
2577f664254SPatrick Williams      *
2587f664254SPatrick Williams      *  @param[in] yield - A yield context to async block upon.
2597f664254SPatrick Williams      *  @param[in] ec - an error code that will be set for any errors
2607f664254SPatrick Williams      *  @param[in] service - The service to call.
2617f664254SPatrick Williams      *  @param[in] objpath - The object's path for the call.
2627f664254SPatrick Williams      *  @param[in] interf - The object's interface to call.
2637f664254SPatrick Williams      *  @param[in] method - The object's method to call.
264ddc57bdfSEd Tanous      *  @param[in] a - Optional parameters for the method call.
2657f664254SPatrick Williams      *
2667f664254SPatrick Williams      *  @return Unpacked value of RetType
2677f664254SPatrick Williams      */
2687f664254SPatrick Williams     template <typename... RetTypes, typename... InputArgs>
yield_method_call(boost::asio::yield_context yield,boost::system::error_code & ec,const std::string & service,const std::string & objpath,const std::string & interf,const std::string & method,const InputArgs &...a)26906f265f6SPatrick Williams     auto yield_method_call(
27006f265f6SPatrick Williams         boost::asio::yield_context yield, boost::system::error_code& ec,
27106f265f6SPatrick Williams         const std::string& service, const std::string& objpath,
2727f664254SPatrick Williams         const std::string& interf, const std::string& method,
2737f664254SPatrick Williams         const InputArgs&... a)
2747f664254SPatrick Williams     {
27510d7aa12SPatrick Williams         message_t m;
2767f664254SPatrick Williams         try
2777f664254SPatrick Williams         {
2787f664254SPatrick Williams             m = new_method_call(service.c_str(), objpath.c_str(),
2797f664254SPatrick Williams                                 interf.c_str(), method.c_str());
2807f664254SPatrick Williams             m.append(a...);
2817f664254SPatrick Williams         }
2827f664254SPatrick Williams         catch (const exception::SdBusError& e)
2837f664254SPatrick Williams         {
2847f664254SPatrick Williams             ec = boost::system::errc::make_error_code(
2857f664254SPatrick Williams                 static_cast<boost::system::errc::errc_t>(e.get_errno()));
2867f664254SPatrick Williams         }
2877f664254SPatrick Williams         if (!ec)
2887f664254SPatrick Williams         {
289dfbd9ddfSLei YU             message_t r;
29050fe983aSEd Tanous             r = async_send_yield(m, yield[ec]);
2917f664254SPatrick Williams             try
2927f664254SPatrick Williams             {
293dfbd9ddfSLei YU                 return r.unpack<RetTypes...>();
2947f664254SPatrick Williams             }
2955a6c7902SBrad Bishop             catch (const std::exception&)
2967f664254SPatrick Williams             {
2977f664254SPatrick Williams                 ec = boost::system::errc::make_error_code(
2987f664254SPatrick Williams                     boost::system::errc::invalid_argument);
2997f664254SPatrick Williams             }
3007f664254SPatrick Williams         }
301dfbd9ddfSLei YU         return default_ret_types<RetTypes...>();
3027f664254SPatrick Williams     }
3031778b12bSEd Tanous #endif
get_io_context()3047f664254SPatrick Williams     boost::asio::io_context& get_io_context()
3057f664254SPatrick Williams     {
3067f664254SPatrick Williams         return io_;
3077f664254SPatrick Williams     }
3087f664254SPatrick Williams 
3097f664254SPatrick Williams   private:
3107f664254SPatrick Williams     boost::asio::io_context& io_;
3117f664254SPatrick Williams     boost::asio::posix::stream_descriptor socket;
312cd3bf08aSEd Tanous     boost::asio::steady_timer timer;
3137f664254SPatrick Williams 
process()314cd3bf08aSEd Tanous     void process()
3157f664254SPatrick Williams     {
316cd3bf08aSEd Tanous         if (process_discard())
317cd3bf08aSEd Tanous         {
318cd3bf08aSEd Tanous             read_immediate();
319cd3bf08aSEd Tanous         }
320cd3bf08aSEd Tanous         else
321cd3bf08aSEd Tanous         {
322cd3bf08aSEd Tanous             read_wait();
323cd3bf08aSEd Tanous         }
324cd3bf08aSEd Tanous     }
325cd3bf08aSEd Tanous 
on_fd_event(const boost::system::error_code & ec)326cd3bf08aSEd Tanous     void on_fd_event(const boost::system::error_code& ec)
327cd3bf08aSEd Tanous     {
328cd3bf08aSEd Tanous         // This is expected if the timer expired before an fd event was
329cd3bf08aSEd Tanous         // available
330cd3bf08aSEd Tanous         if (ec == boost::asio::error::operation_aborted)
331cd3bf08aSEd Tanous         {
332cd3bf08aSEd Tanous             return;
333cd3bf08aSEd Tanous         }
334cd3bf08aSEd Tanous         timer.cancel();
3350c76546fSVernon Mauery         if (ec)
3360c76546fSVernon Mauery         {
3370c76546fSVernon Mauery             return;
3380c76546fSVernon Mauery         }
339cd3bf08aSEd Tanous         process();
3407f664254SPatrick Williams     }
341cd3bf08aSEd Tanous 
on_timer_event(const boost::system::error_code & ec)342cd3bf08aSEd Tanous     void on_timer_event(const boost::system::error_code& ec)
3437f664254SPatrick Williams     {
344cd3bf08aSEd Tanous         if (ec == boost::asio::error::operation_aborted)
345cd3bf08aSEd Tanous         {
346cd3bf08aSEd Tanous             // This is expected if the fd was available before the timer expired
347cd3bf08aSEd Tanous             return;
3487f664254SPatrick Williams         }
349cd3bf08aSEd Tanous         if (ec)
350cd3bf08aSEd Tanous         {
351cd3bf08aSEd Tanous             return;
352cd3bf08aSEd Tanous         }
353cd3bf08aSEd Tanous         // Abort existing operations on the socket
354cd3bf08aSEd Tanous         socket.cancel();
355cd3bf08aSEd Tanous         process();
356cd3bf08aSEd Tanous     }
357cd3bf08aSEd Tanous 
read_wait()358cd3bf08aSEd Tanous     void read_wait()
359cd3bf08aSEd Tanous     {
360cd3bf08aSEd Tanous         int fd = get_fd();
361cd3bf08aSEd Tanous         if (fd < 0)
362cd3bf08aSEd Tanous         {
363cd3bf08aSEd Tanous             return;
364cd3bf08aSEd Tanous         }
365cd3bf08aSEd Tanous         if (fd != socket.native_handle())
366cd3bf08aSEd Tanous         {
367cd3bf08aSEd Tanous             socket.release();
368cd3bf08aSEd Tanous             socket.assign(fd);
369cd3bf08aSEd Tanous         }
370cd3bf08aSEd Tanous         int events = get_events();
371cd3bf08aSEd Tanous         if (events < 0)
372cd3bf08aSEd Tanous         {
373cd3bf08aSEd Tanous             return;
374cd3bf08aSEd Tanous         }
375cd3bf08aSEd Tanous         if (events & POLLIN)
376cd3bf08aSEd Tanous         {
377cd3bf08aSEd Tanous             socket.async_wait(boost::asio::posix::stream_descriptor::wait_read,
378cd3bf08aSEd Tanous                               std::bind_front(&connection::on_fd_event, this));
379cd3bf08aSEd Tanous         }
380cd3bf08aSEd Tanous         if (events & POLLOUT)
381cd3bf08aSEd Tanous         {
382cd3bf08aSEd Tanous             socket.async_wait(boost::asio::posix::stream_descriptor::wait_write,
383cd3bf08aSEd Tanous                               std::bind_front(&connection::on_fd_event, this));
384cd3bf08aSEd Tanous         }
385cd3bf08aSEd Tanous         if (events & POLLERR)
386cd3bf08aSEd Tanous         {
387cd3bf08aSEd Tanous             socket.async_wait(boost::asio::posix::stream_descriptor::wait_error,
388cd3bf08aSEd Tanous                               std::bind_front(&connection::on_fd_event, this));
389cd3bf08aSEd Tanous         }
390cd3bf08aSEd Tanous 
391cd3bf08aSEd Tanous         uint64_t timeout = 0;
392cd3bf08aSEd Tanous         int timeret = get_timeout(&timeout);
393cd3bf08aSEd Tanous         if (timeret < 0)
394cd3bf08aSEd Tanous         {
395cd3bf08aSEd Tanous             return;
396cd3bf08aSEd Tanous         }
397cd3bf08aSEd Tanous         using clock = std::chrono::steady_clock;
398cd3bf08aSEd Tanous 
399cd3bf08aSEd Tanous         using SdDuration = std::chrono::duration<uint64_t, std::micro>;
400cd3bf08aSEd Tanous         SdDuration sdTimeout(timeout);
401cd3bf08aSEd Tanous         // sd-bus always returns a 64 bit timeout regardless of architecture,
402cd3bf08aSEd Tanous         // and per the documentation routinely returns UINT64_MAX
403cd3bf08aSEd Tanous         if (sdTimeout > clock::duration::max())
404cd3bf08aSEd Tanous         {
405cd3bf08aSEd Tanous             // No need to start the timer if the expiration is longer than
406cd3bf08aSEd Tanous             // underlying timer can run.
407cd3bf08aSEd Tanous             return;
408cd3bf08aSEd Tanous         }
409cd3bf08aSEd Tanous         auto nativeTimeout = std::chrono::floor<clock::duration>(sdTimeout);
410cd3bf08aSEd Tanous         timer.expires_at(clock::time_point(nativeTimeout));
411cd3bf08aSEd Tanous         timer.async_wait(std::bind_front(&connection::on_timer_event, this));
4127f664254SPatrick Williams     }
read_immediate()4137f664254SPatrick Williams     void read_immediate()
4147f664254SPatrick Williams     {
415cd3bf08aSEd Tanous         boost::asio::post(io_, std::bind_front(&connection::process, this));
4167f664254SPatrick Williams     }
4177f664254SPatrick Williams };
4187f664254SPatrick Williams 
4197f664254SPatrick Williams } // namespace asio
4207f664254SPatrick Williams 
4217f664254SPatrick Williams } // namespace sdbusplus
422