Line data Source code
1 : /* 2 : * Copyright (c) 2021 Project CHIP Authors 3 : * 4 : * Licensed under the Apache License, Version 2.0 (the "License"); 5 : * you may not use this file except in compliance with the License. 6 : * You may obtain a copy of the License at 7 : * 8 : * http://www.apache.org/licenses/LICENSE-2.0 9 : * 10 : * Unless required by applicable law or agreed to in writing, software 11 : * distributed under the License is distributed on an "AS IS" BASIS, 12 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 : * See the License for the specific language governing permissions and 14 : * limitations under the License. 15 : */ 16 : 17 : #pragma once 18 : 19 : #include <access/SubjectDescriptor.h> 20 : #include <credentials/FabricTable.h> 21 : #include <lib/core/CHIPConfig.h> 22 : #include <lib/core/Optional.h> 23 : #include <lib/core/PeerId.h> 24 : #include <lib/core/ScopedNodeId.h> 25 : #include <lib/support/IntrusiveList.h> 26 : #include <lib/support/ReferenceCountedHandle.h> 27 : #include <messaging/ReliableMessageProtocolConfig.h> 28 : #include <messaging/SessionParameters.h> 29 : #include <platform/LockTracker.h> 30 : #include <transport/SessionDelegate.h> 31 : 32 : namespace chip { 33 : namespace Transport { 34 : class Session; 35 : } // namespace Transport 36 : 37 : /** @brief 38 : * Non-copyable session reference. All SessionHandles are created within SessionManager. It is not allowed to store SessionHandle 39 : * anywhere except for function arguments and return values. 40 : * 41 : * SessionHandle is reference counted such that it is never dangling, but there can be a gray period when the session is marked 42 : * as pending removal but not actually removed yet. During this period, the handle is functional, but the underlying session 43 : * won't be able to be grabbed by any SessionHolder. SessionHandle->IsActiveSession can be used to check if the session is 44 : * active. 45 : */ 46 : class SessionHandle 47 : { 48 : public: 49 459 : SessionHandle(Transport::Session & session) : mSession(session) {} 50 27 : ~SessionHandle() {} 51 : 52 : SessionHandle(const SessionHandle &) = delete; 53 : SessionHandle operator=(const SessionHandle &) = delete; 54 33442 : SessionHandle(SessionHandle &&) = default; 55 : SessionHandle & operator=(SessionHandle &&) = delete; 56 : 57 : bool operator==(const SessionHandle & that) const { return &mSession.Get() == &that.mSession.Get(); } 58 : 59 114763 : Transport::Session * operator->() const { return mSession.operator->(); } 60 : 61 : private: 62 : friend class SessionHolder; 63 : ReferenceCountedHandle<Transport::Session> mSession; 64 : }; 65 : 66 : /** @brief 67 : * Managed session reference. The object is used to store a session, the stored session will be automatically 68 : * released when the underlying session is released. One must verify it is available before use. The object can be 69 : * created using SessionHandle.Grab() 70 : */ 71 : class SessionHolder : public IntrusiveListNodeBase<> 72 : { 73 : public: 74 3 : SessionHolder() {} 75 0 : SessionHolder(const SessionHandle & handle) { Grab(handle); } 76 : virtual ~SessionHolder(); 77 : 78 : SessionHolder(const SessionHolder &); 79 : SessionHolder(SessionHolder && that); 80 : SessionHolder & operator=(const SessionHolder &); 81 : SessionHolder & operator=(SessionHolder && that); 82 : 83 1319 : virtual void SessionReleased() { Release(); } 84 0 : virtual void ShiftToSession(const SessionHandle & session) 85 : { 86 0 : Release(); 87 0 : Grab(session); 88 0 : } 89 : 90 11855 : bool Contains(const SessionHandle & session) const 91 : { 92 11855 : return mSession.HasValue() && &mSession.Value().Get() == &session.mSession.Get(); 93 : } 94 : 95 : bool GrabPairingSession(const SessionHandle & session); // Should be only used inside CASE/PASE pairing. 96 : bool Grab(const SessionHandle & session); 97 : void Release(); 98 : 99 93049 : explicit operator bool() const { return mSession.HasValue(); } 100 31779 : Optional<SessionHandle> Get() const 101 : { 102 : // 103 : // We cannot return mSession directly even if Optional<SessionHandle> is internally composed of the same bits, 104 : // since they are not actually equivalent type-wise, and SessionHandle does not permit copy-construction. 105 : // 106 : // So, construct a new Optional<SessionHandle> from the underlying Transport::Session reference. 107 : // 108 63558 : return mSession.HasValue() ? chip::MakeOptional<SessionHandle>(mSession.Value().Get()) 109 63558 : : chip::Optional<SessionHandle>::Missing(); 110 : } 111 : 112 64238 : Transport::Session * operator->() const { return &mSession.Value().Get(); } 113 : 114 : // There is not delegate, nothing to do here 115 11 : virtual void DispatchSessionEvent(SessionDelegate::Event event) {} 116 : 117 : protected: 118 : // Helper for use by the Grab methods. 119 : void GrabUnchecked(const SessionHandle & session); 120 : 121 : Optional<ReferenceCountedHandle<Transport::Session>> mSession; 122 : }; 123 : 124 : /// @brief Extends SessionHolder to allow propagate SessionDelegate::* events to a given destination 125 : class SessionHolderWithDelegate : public SessionHolder 126 : { 127 : public: 128 3231 : SessionHolderWithDelegate(SessionDelegate & delegate) : mDelegate(delegate) {} 129 : SessionHolderWithDelegate(const SessionHandle & handle, SessionDelegate & delegate) : SessionHolder(handle), mDelegate(delegate) 130 : {} 131 85750 : operator bool() const { return SessionHolder::operator bool(); } 132 : 133 43 : void SessionReleased() override 134 : { 135 43 : Release(); 136 : 137 : // Note, the session is already cleared during mDelegate.OnSessionReleased 138 43 : mDelegate.OnSessionReleased(); 139 43 : } 140 : 141 0 : void ShiftToSession(const SessionHandle & session) override 142 : { 143 0 : if (mDelegate.GetNewSessionHandlingPolicy() == SessionDelegate::NewSessionHandlingPolicy::kShiftToNewSession) 144 0 : SessionHolder::ShiftToSession(session); 145 0 : } 146 : 147 8 : void DispatchSessionEvent(SessionDelegate::Event event) override { (mDelegate.*event)(); } 148 : 149 : private: 150 : SessionDelegate & mDelegate; 151 : }; 152 : 153 : namespace Transport { 154 : 155 : class SecureSession; 156 : class UnauthenticatedSession; 157 : class IncomingGroupSession; 158 : class OutgoingGroupSession; 159 : 160 : class Session 161 : { 162 : public: 163 133776 : virtual ~Session() {} 164 : 165 : enum class SessionType : uint8_t 166 : { 167 : kUndefined = 0, 168 : kUnauthenticated = 1, 169 : kSecure = 2, 170 : kGroupIncoming = 3, 171 : kGroupOutgoing = 4, 172 : }; 173 : 174 : virtual SessionType GetSessionType() const = 0; 175 : 176 8129 : void AddHolder(SessionHolder & holder) 177 : { 178 8129 : assertChipStackLockedByCurrentThread(); 179 8129 : VerifyOrDie(!holder.IsInList()); 180 8129 : mHolders.PushBack(&holder); 181 8129 : } 182 : 183 8129 : void RemoveHolder(SessionHolder & holder) 184 : { 185 8129 : assertChipStackLockedByCurrentThread(); 186 8129 : VerifyOrDie(mHolders.Contains(&holder)); 187 8129 : mHolders.Remove(&holder); 188 8129 : } 189 : 190 : virtual void Retain() = 0; 191 : virtual void Release() = 0; 192 : 193 : virtual bool IsActiveSession() const = 0; 194 : 195 : virtual ScopedNodeId GetPeer() const = 0; 196 : virtual ScopedNodeId GetLocalScopedNodeId() const = 0; 197 : virtual Access::SubjectDescriptor GetSubjectDescriptor() const = 0; 198 : virtual bool AllowsMRP() const = 0; 199 : virtual bool AllowsLargePayload() const = 0; 200 : virtual const SessionParameters & GetRemoteSessionParameters() const = 0; 201 : virtual System::Clock::Timestamp GetMRPBaseTimeout() const = 0; 202 : virtual System::Clock::Milliseconds32 GetAckTimeout() const = 0; 203 : 204 9366 : const ReliableMessageProtocolConfig & GetRemoteMRPConfig() const { return GetRemoteSessionParameters().GetMRPConfig(); } 205 : 206 : // Returns a suggested timeout value based on the round-trip time it takes for the peer at the other end of the session to 207 : // receive a message, process it and send it back. This is computed based on the session type, the type of transport, sleepy 208 : // characteristics of the target and a caller-provided value for the time it takes to process a message at the upper layer on 209 : // the target For group sessions, this function will always return 0. 210 : System::Clock::Timeout ComputeRoundTripTimeout(System::Clock::Timeout upperlayerProcessingTimeout); 211 : 212 68591 : FabricIndex GetFabricIndex() const { return mFabricIndex; } 213 : 214 : SecureSession * AsSecureSession(); 215 : UnauthenticatedSession * AsUnauthenticatedSession(); 216 : IncomingGroupSession * AsIncomingGroupSession(); 217 : OutgoingGroupSession * AsOutgoingGroupSession(); 218 : 219 39990 : bool IsGroupSession() const 220 : { 221 39990 : return GetSessionType() == SessionType::kGroupIncoming || GetSessionType() == SessionType::kGroupOutgoing; 222 : } 223 : 224 9546 : bool IsSecureSession() const { return GetSessionType() == SessionType::kSecure; } 225 : 226 42 : bool IsUnauthenticatedSession() const { return GetSessionType() == SessionType::kUnauthenticated; } 227 : 228 8 : void DispatchSessionEvent(SessionDelegate::Event event) 229 : { 230 : // Holders might remove themselves when notified. 231 8 : auto holder = mHolders.begin(); 232 27 : while (holder != mHolders.end()) 233 : { 234 19 : auto cur = holder; 235 19 : ++holder; 236 19 : cur->DispatchSessionEvent(event); 237 : } 238 8 : } 239 : 240 : // Return a session id that is usable for logging. This is the local session 241 : // id for secure unicast sessions, 0 for non-secure unicast sessions, and 242 : // the group id for group sessions. 243 : uint16_t SessionIdForLogging() const; 244 : 245 : protected: 246 : // This should be called by sub-classes at the very beginning of the destructor, before any data field is disposed, such that 247 : // the session is still functional during the callback. 248 133621 : void NotifySessionReleased() 249 : { 250 133621 : SessionHandle session(*this); 251 133652 : while (!mHolders.Empty()) 252 : { 253 31 : mHolders.begin()->SessionReleased(); // SessionReleased must remove the item from the linked list 254 : } 255 133621 : } 256 : 257 1517 : void SetFabricIndex(FabricIndex index) { mFabricIndex = index; } 258 : 259 : const SecureSession * AsConstSecureSession() const; 260 : const IncomingGroupSession * AsConstIncomingGroupSession() const; 261 : const OutgoingGroupSession * AsConstOutgoingGroupSession() const; 262 : 263 : IntrusiveList<SessionHolder> mHolders; 264 : 265 : private: 266 : FabricIndex mFabricIndex = kUndefinedFabricIndex; 267 : }; 268 : 269 : // 270 : // Return a string representation of the underlying session. 271 : // 272 : // Always returns a non-null pointer. 273 : // 274 : const char * GetSessionTypeString(const SessionHandle & session); 275 : 276 : } // namespace Transport 277 : } // namespace chip