1 #include "sdbusplus/server/transaction.hpp"
2 
3 namespace sdbusplus
4 {
5 namespace server
6 {
7 namespace transaction
8 {
9 namespace details
10 {
11 
12 // Transaction Id
13 thread_local uint64_t id = 0;
14 
15 } // namespace details
16 
17 uint64_t get_id()
18 {
19     // If the transaction id has not been initialized, generate one.
20     if (!details::id)
21     {
22         details::Transaction t;
23         details::id = std::hash<details::Transaction>{}(t);
24     }
25     return details::id;
26 }
27 
28 void set_id(uint64_t value)
29 {
30     details::id = value;
31 }
32 
33 void set_id(message::message& msg)
34 {
35     auto tbus = msg.get_bus();
36     auto t = Transaction(tbus, msg);
37     set_id(std::hash<Transaction>{}(t));
38 }
39 
40 } // namespace transaction
41 } // namespace server
42 } // namespace sdbusplus
43 
44 namespace std
45 {
46 
47 size_t hash<sdbusplus::bus::bus>::operator()(sdbusplus::bus::bus& b) const
48 {
49     auto name = b.get_unique_name();
50     return std::hash<std::string>{}(name);
51 }
52 
53 size_t hash<sdbusplus::message::message>::operator()(
54     sdbusplus::message::message& m) const
55 {
56     switch (m.get_type())
57     {
58         // Reply messages will always embed the cookie of the original
59         // message in a separate location. We want to use this cookie
60         // to correlate messages as one transaction.
61         case SD_BUS_MESSAGE_METHOD_RETURN:
62         case SD_BUS_MESSAGE_METHOD_ERROR:
63             return std::hash<uint64_t>{}(m.get_reply_cookie());
64         // Method calls will have the cookie in the header when sealed.
65         // Since we are on the server side that should always be the case.
66         case SD_BUS_MESSAGE_METHOD_CALL:
67             return std::hash<uint64_t>{}(m.get_cookie());
68         // Outgoing signals don't have a cookie so we need to use
69         // something else as an id. Just use a monotonic unique one.
70         case SD_BUS_MESSAGE_SIGNAL:
71             return std::hash<uint64_t>{}(
72                 std::chrono::steady_clock::now().time_since_epoch().count());
73         default:
74             throw std::runtime_error("hash message: Unknown message type");
75     }
76 }
77 
78 size_t hash<sdbusplus::server::transaction::Transaction>::operator()(
79     sdbusplus::server::transaction::Transaction const& t) const
80 {
81     auto hash1 = std::hash<sdbusplus::bus::bus>{}(t.bus);
82     auto hash2 = std::hash<sdbusplus::message::message>{}(t.msg);
83 
84     // boost::hash_combine() algorithm.
85     return static_cast<size_t>(
86         hash1 ^ (hash2 + 0x9e3779b9 + (hash1 << 6) + (hash1 >> 2)));
87 }
88 
89 size_t hash<sdbusplus::server::transaction::details::Transaction>::operator()(
90     sdbusplus::server::transaction::details::Transaction const& t) const
91 {
92     auto hash1 = std::hash<int>{}(t.time);
93     auto hash2 = std::hash<std::thread::id>{}(t.thread);
94 
95     // boost::hash_combine() algorithm.
96     return static_cast<size_t>(
97         hash1 ^ (hash2 + 0x9e3779b9 + (hash1 << 6) + (hash1 >> 2)));
98 }
99 } // namespace std
100