WebTransportSessionProxy.h (9141B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #ifndef mozilla_net_WebTransportProxy_h 7 #define mozilla_net_WebTransportProxy_h 8 9 #include <functional> 10 #include "nsIChannelEventSink.h" 11 #include "nsIInterfaceRequestor.h" 12 #include "nsIRedirectResultListener.h" 13 #include "nsIStreamListener.h" 14 #include "nsIWebTransport.h" 15 16 /* 17 * WebTransportSessionProxy is introduced to enable the creation of a 18 * Http3WebTransportSession and coordination of actions that are performed on 19 * the main thread and on the socket thread. 20 * 21 * mChannel, mRedirectChannel, and mListener are used only on the main thread. 22 * 23 * mWebTransportSession is used only on the socket thread. 24 * 25 * mState and mSessionId are used on both threads, socket and main thread and it 26 * is only used with a lock. 27 * 28 * 29 * WebTransportSessionProxyState: 30 * - INIT: before AsyncConnect is called. 31 * 32 * - NEGOTIATING: It is set during AsyncConnect. During this state HttpChannel 33 * is open but OnStartRequest has not been called yet. This state can 34 * transfer into: 35 * - NEGOTIATING_SUCCEEDED: when a Http3WebTransportSession has been 36 * negotiated. 37 * - DONE: when a WebTransport session has been canceled. 38 * 39 * - NEGOTIATING_SUCCEEDED: It is set during parsing of 40 * Http3WebTransportSession response when the response has been successful. 41 * mWebTransport is set to the Http3WebTransportSession at the same time the 42 * session changes to this state. This state can transfer into: 43 * - ACTIVE: during the OnStopRequest call if the WebTransport has not been 44 * canceled or failed for other reason, e.g. a browser shutdown or content 45 * blocking policies. 46 * - SESSION_CLOSE_PENDING: if the WebTransport has been canceled via an API 47 * call or content blocking policies. (the main thread initiated close). 48 * - CLOSE_CALLBACK_PENDING: if Http3WebTransportSession has been canceled 49 * due to a shutdown or a server closing a session. (the socket thread 50 * initiated close). 51 * 52 * - ACTIVE: In this state the session is negotiated and ready to use. This 53 * state can transfer into: 54 * - SESSION_CLOSE_PENDING: if the WebTransport has been canceled via an API 55 * call(nsIWebTransport::closeSession) or content blocking policies. (the 56 * main thread initiated close). 57 * - CLOSE_CALLBACK_PENDING: if Http3WebTransportSession has been canceled 58 * due to a shutdown or a server closing a session. (the socket thread 59 * initiated close). 60 * 61 * - CLOSE_CALLBACK_PENDING: This is the socket thread initiated close. In this 62 * state, the Http3WebTransportSession has been closed and a 63 * CallOnSessionClosed call is dispatched to the main thread to call the 64 * appropriate listener. 65 * 66 * - SESSION_CLOSE_PENDING: This is the main thread initiated close. In this 67 * state, the WebTransport has been closed via an API call 68 * (nsIWebTransport::closeSession) and a CloseSessionInternal call is 69 * dispatched to the socket thread to close the appropriate 70 * Http3WebTransportSession. 71 * 72 * - DONE: everything has been cleaned up on both threads. 73 * 74 * 75 * AsyncConnect creates mChannel on the main thread. Redirect callbacks are also 76 * performed on the main thread (mRedirectChannel set and access only on the 77 * main thread). Before this point, there are no activities on the socket thread 78 * and Http3WebTransportSession is nullptr. mChannel is going to create a 79 * nsHttpTransaction. The transaction will be dispatched on a nsAHttpConnection, 80 * i.e. currently only the HTTP/3 version is implemented, therefore this will be 81 * a HttpConnectionUDP and a Http3Session. The Http3Session creates a 82 * Http3WebTransportSession. Until a response is received 83 * Http3WebTransportSession is only accessed by Http3Session. During parsing of 84 * a successful received from a server on the socket thread, 85 * WebTransportSessionProxy::mWebTransportSession will take a reference to 86 * Http3WebTransportSession and mState will be set to NEGOTIATING_SUCCEEDED. 87 * From now on WebTransportSessionProxy is responsible for closing 88 * Http3WebTransportSession if the closing of the session is initiated on the 89 * main thread. OnStartRequest and OnStopRequest will be called on the main 90 * thread. The session negotiation can have 2 outcomes: 91 * - If both calls, i.e. OnStartRequest an OnStopRequest, indicate that the 92 * request has succeeded and mState is NEGOTIATING_SUCCEEDED, the 93 * mListener->OnSessionReady will be called during OnStopRequest. 94 * - Otherwise, mListener->OnSessionClosed will be called, the state transferred 95 * into SESSION_CLOSE_PENDING, and CloseSessionInternal will be dispatched to 96 * the socket thread. 97 * 98 * CloseSession is called on the main thread. If the session is already closed 99 * it returns an error. If the session is in state NEGOTIATING or 100 * NEGOTIATING_SUCCEEDED mChannel will be canceled. If the session is in state 101 * NEGOTIATING_SUCCEEDED or ACTIVE the state transferred into 102 * SESSION_CLOSE_PENDING, and CloseSessionInternal will be dispatched to the 103 * socket thread 104 * 105 * OnSessionReadyInternal is called on the socket thread. If mState is 106 * NEGOTIATING the state will be set to NEGOTIATING_SUCCEEDED and mWebTransport 107 * will be set to the newly negotiated Http3WebTransportSession. If mState is 108 * DONE, the Http3WebTransportSession will be close. 109 * 110 * OnSessionClosed is called on the socket thread. mState will be set to 111 * CLOSE_CALLBACK_PENDING and CallOnSessionClosed will be dispatched to the main 112 * thread. 113 * 114 * mWebTransport is set during states NEGOTIATING_SUCCEEDED, ACTIVE and 115 * SESSION_CLOSE_PENDING. 116 */ 117 118 namespace mozilla::net { 119 120 class WebTransportEventService; 121 122 class WebTransportStreamCallbackWrapper; 123 124 class WebTransportSessionProxy final 125 : public nsIWebTransport, 126 public WebTransportSessionEventListener, 127 public WebTransportSessionEventListenerInternal, 128 public WebTransportConnectionSettings, 129 public nsIStreamListener, 130 public nsIChannelEventSink, 131 public nsIRedirectResultListener, 132 public nsIInterfaceRequestor { 133 public: 134 NS_DECL_THREADSAFE_ISUPPORTS 135 NS_DECL_NSIWEBTRANSPORT 136 NS_DECL_WEBTRANSPORTSESSIONEVENTLISTENER 137 NS_DECL_WEBTRANSPORTSESSIONEVENTLISTENERINTERNAL 138 NS_DECL_WEBTRANSPORTCONNECTIONSETTINGS 139 NS_DECL_NSIREQUESTOBSERVER 140 NS_DECL_NSISTREAMLISTENER 141 NS_DECL_NSICHANNELEVENTSINK 142 NS_DECL_NSIREDIRECTRESULTLISTENER 143 NS_DECL_NSIINTERFACEREQUESTOR 144 145 WebTransportSessionProxy(); 146 147 private: 148 ~WebTransportSessionProxy(); 149 150 void CloseSessionInternal(); 151 void CloseSessionInternalLocked(); 152 void CallOnSessionClosed(); 153 void CallOnSessionClosedLocked(); 154 155 enum WebTransportSessionProxyState { 156 INIT, 157 NEGOTIATING, 158 NEGOTIATING_SUCCEEDED, 159 ACTIVE, 160 CLOSE_CALLBACK_PENDING, 161 SESSION_CLOSE_PENDING, 162 DONE, 163 }; 164 mozilla::Mutex mMutex; 165 WebTransportSessionProxyState mState MOZ_GUARDED_BY(mMutex) = 166 WebTransportSessionProxyState::INIT; 167 void ChangeState(WebTransportSessionProxyState newState); 168 void CreateStreamInternal(nsIWebTransportStreamCallback* callback, 169 bool aBidi); 170 void DoCreateStream(WebTransportStreamCallbackWrapper* aCallback, 171 WebTransportSessionBase* aSession, bool aBidi); 172 void SendDatagramInternal(const RefPtr<WebTransportSessionBase>& aSession, 173 nsTArray<uint8_t>&& aData, uint64_t aTrackingId); 174 void NotifyDatagramReceived(nsTArray<uint8_t>&& aData); 175 void GetMaxDatagramSizeInternal( 176 const RefPtr<WebTransportSessionBase>& aSession); 177 void OnMaxDatagramSizeInternal(uint64_t aSize); 178 void OnOutgoingDatagramOutComeInternal( 179 uint64_t aId, WebTransportSessionEventListener::DatagramOutcome aOutCome); 180 181 nsCOMPtr<nsIChannel> mChannel; 182 uint64_t mHttpChannelID = 0; 183 nsCOMPtr<nsIChannel> mRedirectChannel; 184 RefPtr<WebTransportEventService> mService; 185 nsCOMPtr<WebTransportSessionEventListener> mListener MOZ_GUARDED_BY(mMutex); 186 RefPtr<WebTransportSessionBase> mWebTransportSession MOZ_GUARDED_BY(mMutex); 187 uint64_t mSessionId MOZ_GUARDED_BY(mMutex) = UINT64_MAX; 188 uint32_t mCloseStatus MOZ_GUARDED_BY(mMutex) = 0; 189 nsCString mReason MOZ_GUARDED_BY(mMutex); 190 bool mCleanly MOZ_GUARDED_BY(mMutex) = false; 191 bool mStopRequestCalled MOZ_GUARDED_BY(mMutex) = false; 192 // This is used to store events happened before OnSessionReady. 193 // Note that these events will be dispatched to the socket thread. 194 nsTArray<std::function<void()>> mPendingEvents MOZ_GUARDED_BY(mMutex); 195 nsTArray<std::function<void(nsresult)>> mPendingCreateStreamEvents 196 MOZ_GUARDED_BY(mMutex); 197 nsCOMPtr<nsIEventTarget> mTarget MOZ_GUARDED_BY(mMutex); 198 nsTArray<RefPtr<nsIWebTransportHash>> mServerCertHashes; 199 bool mDedicatedConnection; // for WebTranport 200 nsIWebTransport::HTTPVersion mHTTPVersion = nsIWebTransport::HTTPVersion::h3; 201 }; 202 203 } // namespace mozilla::net 204 205 #endif // mozilla_net_WebTransportProxy_h