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_t& 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_t>::operator()(sdbusplus::bus_t& 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_t>::operator()(sdbusplus::message_t& m) const 54 { 55 switch (m.get_type()) 56 { 57 // Reply messages will always embed the cookie of the original 58 // message in a separate location. We want to use this cookie 59 // to correlate messages as one transaction. 60 case SD_BUS_MESSAGE_METHOD_RETURN: 61 case SD_BUS_MESSAGE_METHOD_ERROR: 62 return std::hash<uint64_t>{}(m.get_reply_cookie()); 63 // Method calls will have the cookie in the header when sealed. 64 // Since we are on the server side that should always be the case. 65 case SD_BUS_MESSAGE_METHOD_CALL: 66 return std::hash<uint64_t>{}(m.get_cookie()); 67 // Outgoing signals don't have a cookie so we need to use 68 // something else as an id. Just use a monotonic unique one. 69 case SD_BUS_MESSAGE_SIGNAL: 70 return std::hash<uint64_t>{}( 71 std::chrono::steady_clock::now().time_since_epoch().count()); 72 default: 73 throw std::runtime_error("hash message: Unknown message type"); 74 } 75 } 76 77 size_t hash<sdbusplus::server::transaction::Transaction>::operator()( 78 const sdbusplus::server::transaction::Transaction& t) const 79 { 80 auto hash1 = std::hash<sdbusplus::bus_t>{}(t.bus); 81 auto hash2 = std::hash<sdbusplus::message_t>{}(t.msg); 82 83 // boost::hash_combine() algorithm. 84 return static_cast<size_t>( 85 hash1 ^ (hash2 + 0x9e3779b9 + (hash1 << 6) + (hash1 >> 2))); 86 } 87 88 size_t hash<sdbusplus::server::transaction::details::Transaction>::operator()( 89 const sdbusplus::server::transaction::details::Transaction& t) const 90 { 91 auto hash1 = std::hash<std::time_t>{}(t.time); 92 auto hash2 = std::hash<std::thread::id>{}(t.thread); 93 94 // boost::hash_combine() algorithm. 95 return static_cast<size_t>( 96 hash1 ^ (hash2 + 0x9e3779b9 + (hash1 << 6) + (hash1 >> 2))); 97 } 98 } // namespace std 99