1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=4 sw=2 sts=2 et cin: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 // HttpLog.h should generally be included first
8 #include "HttpLog.h"
9 
10 // Log on level :5, instead of default :4.
11 #undef LOG
12 #define LOG(args) LOG5(args)
13 #undef LOG_ENABLED
14 #define LOG_ENABLED() LOG5_ENABLED()
15 
16 #define TLS_EARLY_DATA_NOT_AVAILABLE 0
17 #define TLS_EARLY_DATA_AVAILABLE_BUT_NOT_USED 1
18 #define TLS_EARLY_DATA_AVAILABLE_AND_USED 2
19 
20 #include "ASpdySession.h"
21 #include "mozilla/Telemetry.h"
22 #include "HttpConnectionUDP.h"
23 #include "nsHttpHandler.h"
24 #include "Http3Session.h"
25 #include "nsISocketProvider.h"
26 #include "nsNetAddr.h"
27 #include "nsINetAddr.h"
28 
29 namespace mozilla {
30 namespace net {
31 
32 //-----------------------------------------------------------------------------
33 // HttpConnectionUDP <public>
34 //-----------------------------------------------------------------------------
35 
HttpConnectionUDP()36 HttpConnectionUDP::HttpConnectionUDP() : mHttpHandler(gHttpHandler) {
37   LOG(("Creating HttpConnectionUDP @%p\n", this));
38 }
39 
~HttpConnectionUDP()40 HttpConnectionUDP::~HttpConnectionUDP() {
41   LOG(("Destroying HttpConnectionUDP @%p\n", this));
42 
43   if (mForceSendTimer) {
44     mForceSendTimer->Cancel();
45     mForceSendTimer = nullptr;
46   }
47 }
48 
Init(nsHttpConnectionInfo * info,nsIDNSRecord * dnsRecord,nsresult status,nsIInterfaceRequestor * callbacks,uint32_t caps)49 nsresult HttpConnectionUDP::Init(nsHttpConnectionInfo* info,
50                                  nsIDNSRecord* dnsRecord, nsresult status,
51                                  nsIInterfaceRequestor* callbacks,
52                                  uint32_t caps) {
53   LOG1(("HttpConnectionUDP::Init this=%p", this));
54   NS_ENSURE_ARG_POINTER(info);
55   NS_ENSURE_TRUE(!mConnInfo, NS_ERROR_ALREADY_INITIALIZED);
56   MOZ_ASSERT(dnsRecord || NS_FAILED(status));
57 
58   mConnInfo = info;
59   MOZ_ASSERT(mConnInfo);
60   MOZ_ASSERT(mConnInfo->IsHttp3());
61 
62   mErrorBeforeConnect = status;
63   mAlpnToken = mConnInfo->GetNPNToken();
64   if (NS_FAILED(mErrorBeforeConnect)) {
65     // See explanation for non-strictness of this operation in
66     // SetSecurityCallbacks.
67     mCallbacks = new nsMainThreadPtrHolder<nsIInterfaceRequestor>(
68         "HttpConnectionUDP::mCallbacks", callbacks, false);
69     return mErrorBeforeConnect;
70   }
71 
72   nsCOMPtr<nsIDNSAddrRecord> dnsAddrRecord = do_QueryInterface(dnsRecord);
73   MOZ_ASSERT(dnsAddrRecord);
74   if (!dnsAddrRecord) {
75     return NS_ERROR_FAILURE;
76   }
77   dnsAddrRecord->IsTRR(&mResolvedByTRR);
78   NetAddr peerAddr;
79   nsresult rv = dnsAddrRecord->GetNextAddr(mConnInfo->GetRoutedHost().IsEmpty()
80                                                ? mConnInfo->OriginPort()
81                                                : mConnInfo->RoutedPort(),
82                                            &peerAddr);
83   if (NS_FAILED(rv)) {
84     return rv;
85   }
86 
87   mSocket = do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv);
88   if (NS_FAILED(rv)) {
89     return rv;
90   }
91 
92   // We need an address here so that we can convey the IP version of the
93   // socket.
94   NetAddr local;
95   memset(&local, 0, sizeof(local));
96   local.raw.family = peerAddr.raw.family;
97   rv = mSocket->InitWithAddress(&local, nullptr, false, 1);
98   if (NS_FAILED(rv)) {
99     mSocket = nullptr;
100     return rv;
101   }
102 
103   rv = mSocket->SetRecvBufferSize(
104       StaticPrefs::network_http_http3_recvBufferSize());
105   if (NS_FAILED(rv)) {
106     LOG(("HttpConnectionUDP::Init SetRecvBufferSize failed %d [this=%p]",
107          static_cast<uint32_t>(rv), this));
108     mSocket->Close();
109     mSocket = nullptr;
110     return rv;
111   }
112 
113   if (peerAddr.raw.family == AF_INET) {
114     rv = mSocket->SetDontFragment(true);
115     if (NS_FAILED(rv)) {
116       LOG(("HttpConnectionUDP::Init SetDontFragment failed %d [this=%p]",
117            static_cast<uint32_t>(rv), this));
118     }
119   }
120 
121   // get the resulting socket address.
122   rv = mSocket->GetLocalAddr(getter_AddRefs(mSelfAddr));
123   if (NS_FAILED(rv)) {
124     mSocket->Close();
125     mSocket = nullptr;
126     return rv;
127   }
128 
129   uint32_t controlFlags = 0;
130   if (caps & NS_HTTP_LOAD_ANONYMOUS) {
131     controlFlags |= nsISocketProvider::ANONYMOUS_CONNECT;
132   }
133   if (mConnInfo->GetPrivate()) {
134     controlFlags |= nsISocketProvider::NO_PERMANENT_STORAGE;
135   }
136   if (((caps & NS_HTTP_BE_CONSERVATIVE) || mConnInfo->GetBeConservative()) &&
137       gHttpHandler->ConnMgr()->BeConservativeIfProxied(
138           mConnInfo->ProxyInfo())) {
139     controlFlags |= nsISocketProvider::BE_CONSERVATIVE;
140   }
141 
142   mPeerAddr = new nsNetAddr(&peerAddr);
143   mHttp3Session = new Http3Session();
144   rv = mHttp3Session->Init(mConnInfo, mSelfAddr, mPeerAddr, this, controlFlags,
145                            callbacks);
146   if (NS_FAILED(rv)) {
147     LOG(
148         ("HttpConnectionUDP::Init mHttp3Session->Init failed "
149          "[this=%p rv=%x]\n",
150          this, static_cast<uint32_t>(rv)));
151     mSocket->Close();
152     mSocket = nullptr;
153     mHttp3Session = nullptr;
154     return rv;
155   }
156 
157   // See explanation for non-strictness of this operation in
158   // SetSecurityCallbacks.
159   mCallbacks = new nsMainThreadPtrHolder<nsIInterfaceRequestor>(
160       "HttpConnectionUDP::mCallbacks", callbacks, false);
161 
162   // Call SyncListen at the end of this function. This call will actually
163   // attach the sockte to SocketTransportService.
164   rv = mSocket->SyncListen(this);
165   if (NS_FAILED(rv)) {
166     mSocket->Close();
167     mSocket = nullptr;
168     return rv;
169   }
170 
171   return NS_OK;
172 }
173 
174 // called on the socket thread
Activate(nsAHttpTransaction * trans,uint32_t caps,int32_t pri)175 nsresult HttpConnectionUDP::Activate(nsAHttpTransaction* trans, uint32_t caps,
176                                      int32_t pri) {
177   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
178   LOG1(("HttpConnectionUDP::Activate [this=%p trans=%p caps=%x]\n", this, trans,
179         caps));
180 
181   if (!mExperienced && !trans->IsNullTransaction()) {
182     // For QUIC we have HttpConnecitonUDP before the actual connection
183     // has been establish so wait for TLS handshake to be finished before
184     // we mark the connection 'experienced'.
185     if (!mExperienced && mHttp3Session && mHttp3Session->IsConnected()) {
186       mExperienced = true;
187     }
188     if (mBootstrappedTimingsSet) {
189       mBootstrappedTimingsSet = false;
190       nsHttpTransaction* hTrans = trans->QueryHttpTransaction();
191       if (hTrans) {
192         hTrans->BootstrapTimings(mBootstrappedTimings);
193       }
194     }
195     mBootstrappedTimings = TimingStruct();
196   }
197 
198   mTransactionCaps = caps;
199   mPriority = pri;
200 
201   NS_ENSURE_ARG_POINTER(trans);
202 
203   // Connection failures are Activated() just like regular transacions.
204   // If we don't have a confirmation of a connected socket then test it
205   // with a write() to get relevant error code.
206   if (NS_FAILED(mErrorBeforeConnect)) {
207     CloseTransaction(nullptr, mErrorBeforeConnect);
208     trans->Close(mErrorBeforeConnect);
209     gHttpHandler->ExcludeHttp3(mConnInfo);
210     return mErrorBeforeConnect;
211   }
212 
213   if (!mHttp3Session->AddStream(trans, pri, mCallbacks)) {
214     MOZ_ASSERT(false);  // this cannot happen!
215     trans->Close(NS_ERROR_ABORT);
216     return NS_ERROR_FAILURE;
217   }
218 
219   Unused << ResumeSend();
220   return NS_OK;
221 }
222 
Close(nsresult reason,bool aIsShutdown)223 void HttpConnectionUDP::Close(nsresult reason, bool aIsShutdown) {
224   LOG(("HttpConnectionUDP::Close [this=%p reason=%" PRIx32 "]\n", this,
225        static_cast<uint32_t>(reason)));
226 
227   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
228 
229   if (mForceSendTimer) {
230     mForceSendTimer->Cancel();
231     mForceSendTimer = nullptr;
232   }
233 
234   if (!mTrafficCategory.IsEmpty()) {
235     HttpTrafficAnalyzer* hta = gHttpHandler->GetHttpTrafficAnalyzer();
236     if (hta) {
237       hta->IncrementHttpConnection(std::move(mTrafficCategory));
238       MOZ_ASSERT(mTrafficCategory.IsEmpty());
239     }
240   }
241   if (mSocket) {
242     mSocket->Close();
243     mSocket = nullptr;
244   }
245 }
246 
DontReuse()247 void HttpConnectionUDP::DontReuse() {
248   LOG(("HttpConnectionUDP::DontReuse %p http3session=%p\n", this,
249        mHttp3Session.get()));
250   mDontReuse = true;
251   if (mHttp3Session) {
252     mHttp3Session->DontReuse();
253   }
254 }
255 
TestJoinConnection(const nsACString & hostname,int32_t port)256 bool HttpConnectionUDP::TestJoinConnection(const nsACString& hostname,
257                                            int32_t port) {
258   if (mHttp3Session && CanDirectlyActivate()) {
259     return mHttp3Session->TestJoinConnection(hostname, port);
260   }
261 
262   return false;
263 }
264 
JoinConnection(const nsACString & hostname,int32_t port)265 bool HttpConnectionUDP::JoinConnection(const nsACString& hostname,
266                                        int32_t port) {
267   if (mHttp3Session && CanDirectlyActivate()) {
268     return mHttp3Session->JoinConnection(hostname, port);
269   }
270 
271   return false;
272 }
273 
CanReuse()274 bool HttpConnectionUDP::CanReuse() {
275   if (NS_FAILED(mErrorBeforeConnect)) {
276     return false;
277   }
278   if (mDontReuse) {
279     return false;
280   }
281 
282   if (mHttp3Session) {
283     return mHttp3Session->CanReuse();
284   }
285   return false;
286 }
287 
CanDirectlyActivate()288 bool HttpConnectionUDP::CanDirectlyActivate() {
289   // return true if a new transaction can be addded to ths connection at any
290   // time through Activate(). In practice this means this is a healthy SPDY
291   // connection with room for more concurrent streams.
292 
293   if (mHttp3Session) {
294     return CanReuse();
295   }
296   return false;
297 }
298 
299 //----------------------------------------------------------------------------
300 // HttpConnectionUDP::nsAHttpConnection compatible methods
301 //----------------------------------------------------------------------------
302 
OnHeadersAvailable(nsAHttpTransaction * trans,nsHttpRequestHead * requestHead,nsHttpResponseHead * responseHead,bool * reset)303 nsresult HttpConnectionUDP::OnHeadersAvailable(nsAHttpTransaction* trans,
304                                                nsHttpRequestHead* requestHead,
305                                                nsHttpResponseHead* responseHead,
306                                                bool* reset) {
307   LOG(
308       ("HttpConnectionUDP::OnHeadersAvailable [this=%p trans=%p "
309        "response-head=%p]\n",
310        this, trans, responseHead));
311 
312   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
313   NS_ENSURE_ARG_POINTER(trans);
314   MOZ_ASSERT(responseHead, "No response head?");
315 
316   DebugOnly<nsresult> rv =
317       responseHead->SetHeader(nsHttp::X_Firefox_Http3, mAlpnToken);
318   MOZ_ASSERT(NS_SUCCEEDED(rv));
319 
320   // deal with 408 Server Timeouts
321   uint16_t responseStatus = responseHead->Status();
322   static const PRIntervalTime k1000ms = PR_MillisecondsToInterval(1000);
323   if (responseStatus == 408) {
324     // If this error could be due to a persistent connection reuse then
325     // we pass an error code of NS_ERROR_NET_RESET to
326     // trigger the transaction 'restart' mechanism.  We tell it to reset its
327     // response headers so that it will be ready to receive the new response.
328     if (mIsReused &&
329         ((PR_IntervalNow() - mHttp3Session->LastWriteTime()) < k1000ms)) {
330       Close(NS_ERROR_NET_RESET);
331       *reset = true;
332       return NS_OK;
333     }
334   }
335 
336   return NS_OK;
337 }
338 
IsReused()339 bool HttpConnectionUDP::IsReused() { return mIsReused; }
340 
TakeTransport(nsISocketTransport ** aTransport,nsIAsyncInputStream ** aInputStream,nsIAsyncOutputStream ** aOutputStream)341 nsresult HttpConnectionUDP::TakeTransport(
342     nsISocketTransport** aTransport, nsIAsyncInputStream** aInputStream,
343     nsIAsyncOutputStream** aOutputStream) {
344   return NS_ERROR_FAILURE;
345 }
346 
GetSecurityInfo(nsISupports ** secinfo)347 void HttpConnectionUDP::GetSecurityInfo(nsISupports** secinfo) {
348   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
349   LOG(("HttpConnectionUDP::GetSecurityInfo http3Session=%p\n",
350        mHttp3Session.get()));
351 
352   if (mHttp3Session &&
353       NS_SUCCEEDED(mHttp3Session->GetTransactionSecurityInfo(secinfo))) {
354     return;
355   }
356 
357   *secinfo = nullptr;
358 }
359 
PushBack(const char * data,uint32_t length)360 nsresult HttpConnectionUDP::PushBack(const char* data, uint32_t length) {
361   LOG(("HttpConnectionUDP::PushBack [this=%p, length=%d]\n", this, length));
362 
363   return NS_ERROR_UNEXPECTED;
364 }
365 
366 class HttpConnectionUDPForceIO : public Runnable {
367  public:
HttpConnectionUDPForceIO(HttpConnectionUDP * aConn,bool doRecv)368   HttpConnectionUDPForceIO(HttpConnectionUDP* aConn, bool doRecv)
369       : Runnable("net::HttpConnectionUDPForceIO"),
370         mConn(aConn),
371         mDoRecv(doRecv) {}
372 
Run()373   NS_IMETHOD Run() override {
374     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
375 
376     if (mDoRecv) {
377       return mConn->RecvData();
378     }
379 
380     MOZ_ASSERT(mConn->mForceSendPending);
381     mConn->mForceSendPending = false;
382 
383     return mConn->SendData();
384   }
385 
386  private:
387   RefPtr<HttpConnectionUDP> mConn;
388   bool mDoRecv;
389 };
390 
ResumeSend()391 nsresult HttpConnectionUDP::ResumeSend() {
392   LOG(("HttpConnectionUDP::ResumeSend [this=%p]\n", this));
393   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
394   RefPtr<HttpConnectionUDP> self(this);
395   NS_DispatchToCurrentThread(
396       NS_NewRunnableFunction("HttpConnectionUDP::CallSendData",
397                              [self{std::move(self)}]() { self->SendData(); }));
398   return NS_OK;
399 }
400 
ResumeRecv()401 nsresult HttpConnectionUDP::ResumeRecv() { return NS_OK; }
402 
ForceSendIO(nsITimer * aTimer,void * aClosure)403 void HttpConnectionUDP::ForceSendIO(nsITimer* aTimer, void* aClosure) {
404   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
405   HttpConnectionUDP* self = static_cast<HttpConnectionUDP*>(aClosure);
406   MOZ_ASSERT(aTimer == self->mForceSendTimer);
407   self->mForceSendTimer = nullptr;
408   NS_DispatchToCurrentThread(new HttpConnectionUDPForceIO(self, false));
409 }
410 
MaybeForceSendIO()411 nsresult HttpConnectionUDP::MaybeForceSendIO() {
412   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
413   // due to bug 1213084 sometimes real I/O events do not get serviced when
414   // NSPR derived I/O events are ready and this can cause a deadlock with
415   // https over https proxying. Normally we would expect the write callback to
416   // be invoked before this timer goes off, but set it at the old windows
417   // tick interval (kForceDelay) as a backup for those circumstances.
418   static const uint32_t kForceDelay = 17;  // ms
419 
420   if (mForceSendPending) {
421     return NS_OK;
422   }
423   MOZ_ASSERT(!mForceSendTimer);
424   mForceSendPending = true;
425   return NS_NewTimerWithFuncCallback(
426       getter_AddRefs(mForceSendTimer), HttpConnectionUDP::ForceSendIO, this,
427       kForceDelay, nsITimer::TYPE_ONE_SHOT,
428       "net::HttpConnectionUDP::MaybeForceSendIO");
429 }
430 
431 // trigger an asynchronous read
ForceRecv()432 nsresult HttpConnectionUDP::ForceRecv() {
433   LOG(("HttpConnectionUDP::ForceRecv [this=%p]\n", this));
434   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
435 
436   return NS_DispatchToCurrentThread(new HttpConnectionUDPForceIO(this, true));
437 }
438 
439 // trigger an asynchronous write
ForceSend()440 nsresult HttpConnectionUDP::ForceSend() {
441   LOG(("HttpConnectionUDP::ForceSend [this=%p]\n", this));
442   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
443 
444   return MaybeForceSendIO();
445 }
446 
Version()447 HttpVersion HttpConnectionUDP::Version() { return HttpVersion::v3_0; }
448 
449 //-----------------------------------------------------------------------------
450 // HttpConnectionUDP <private>
451 //-----------------------------------------------------------------------------
452 
CloseTransaction(nsAHttpTransaction * trans,nsresult reason,bool aIsShutdown)453 void HttpConnectionUDP::CloseTransaction(nsAHttpTransaction* trans,
454                                          nsresult reason, bool aIsShutdown) {
455   LOG(("HttpConnectionUDP::CloseTransaction[this=%p trans=%p reason=%" PRIx32
456        "]\n",
457        this, trans, static_cast<uint32_t>(reason)));
458 
459   MOZ_ASSERT(trans == mHttp3Session);
460   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
461 
462   if (NS_SUCCEEDED(reason) || (reason == NS_BASE_STREAM_CLOSED)) {
463     MOZ_ASSERT(false);
464     return;
465   }
466 
467   // The connection and security errors clear out alt-svc mappings
468   // in case any previously validated ones are now invalid
469   if (((reason == NS_ERROR_NET_RESET) ||
470        (NS_ERROR_GET_MODULE(reason) == NS_ERROR_MODULE_SECURITY)) &&
471       mConnInfo && !(mTransactionCaps & NS_HTTP_ERROR_SOFTLY)) {
472     gHttpHandler->ClearHostMapping(mConnInfo);
473   }
474 
475   mDontReuse = true;
476   if (mHttp3Session) {
477     mHttp3Session->SetCleanShutdown(aIsShutdown);
478     mHttp3Session->Close(reason);
479     if (!mHttp3Session->IsClosed()) {
480       // During closing phase we still keep mHttp3Session session,
481       // to resend CLOSE_CONNECTION frames.
482       return;
483     }
484   }
485 
486   mHttp3Session = nullptr;
487 
488   {
489     MutexAutoLock lock(mCallbacksLock);
490     mCallbacks = nullptr;
491   }
492 
493   Close(reason, aIsShutdown);
494 
495   // flag the connection as reused here for convenience sake. certainly
496   // it might be going away instead ;-)
497   mIsReused = true;
498 }
499 
OnQuicTimeout(nsITimer * aTimer,void * aClosure)500 void HttpConnectionUDP::OnQuicTimeout(nsITimer* aTimer, void* aClosure) {
501   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
502   LOG(("HttpConnectionUDP::OnQuicTimeout [this=%p]\n", aClosure));
503 
504   HttpConnectionUDP* self = static_cast<HttpConnectionUDP*>(aClosure);
505   self->OnQuicTimeoutExpired();
506 }
507 
OnQuicTimeoutExpired()508 void HttpConnectionUDP::OnQuicTimeoutExpired() {
509   // if the transaction was dropped...
510   if (!mHttp3Session) {
511     LOG(("  no transaction; ignoring event\n"));
512     return;
513   }
514 
515   nsresult rv = mHttp3Session->ProcessOutputAndEvents(mSocket);
516   if (NS_FAILED(rv)) {
517     CloseTransaction(mHttp3Session, rv);
518   }
519 }
520 
521 //-----------------------------------------------------------------------------
522 // HttpConnectionUDP::nsISupports
523 //-----------------------------------------------------------------------------
524 
525 NS_IMPL_ADDREF(HttpConnectionUDP)
NS_IMPL_RELEASE(HttpConnectionUDP)526 NS_IMPL_RELEASE(HttpConnectionUDP)
527 
528 NS_INTERFACE_MAP_BEGIN(HttpConnectionUDP)
529   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
530   NS_INTERFACE_MAP_ENTRY(nsIUDPSocketSyncListener)
531   NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
532   NS_INTERFACE_MAP_ENTRY(HttpConnectionBase)
533   NS_INTERFACE_MAP_ENTRY_CONCRETE(HttpConnectionUDP)
534 NS_INTERFACE_MAP_END
535 
536 // called on the socket transport thread
537 nsresult HttpConnectionUDP::RecvData() {
538   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
539 
540   // if the transaction was dropped...
541   if (!mHttp3Session) {
542     LOG(("  no Http3Session; ignoring event\n"));
543     return NS_OK;
544   }
545 
546   nsresult rv = mHttp3Session->RecvData(mSocket);
547   LOG(("HttpConnectionUDP::OnInputReady %p rv=%" PRIx32, this,
548        static_cast<uint32_t>(rv)));
549 
550   if (NS_FAILED(rv)) CloseTransaction(mHttp3Session, rv);
551 
552   return NS_OK;
553 }
554 
555 // called on the socket transport thread
SendData()556 nsresult HttpConnectionUDP::SendData() {
557   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
558 
559   // if the transaction was dropped...
560   if (!mHttp3Session) {
561     LOG(("  no Http3Session; ignoring event\n"));
562     return NS_OK;
563   }
564 
565   nsresult rv = mHttp3Session->SendData(mSocket);
566   LOG(("HttpConnectionUDP::OnInputReady %p rv=%" PRIx32, this,
567        static_cast<uint32_t>(rv)));
568 
569   if (NS_FAILED(rv)) CloseTransaction(mHttp3Session, rv);
570 
571   return NS_OK;
572 }
573 
574 //-----------------------------------------------------------------------------
575 // HttpConnectionUDP::nsIInterfaceRequestor
576 //-----------------------------------------------------------------------------
577 
578 // not called on the socket transport thread
579 NS_IMETHODIMP
GetInterface(const nsIID & iid,void ** result)580 HttpConnectionUDP::GetInterface(const nsIID& iid, void** result) {
581   // NOTE: This function is only called on the UI thread via sync proxy from
582   //       the socket transport thread.  If that weren't the case, then we'd
583   //       have to worry about the possibility of mHttp3Session going away
584   //       part-way through this function call.  See CloseTransaction.
585 
586   // NOTE - there is a bug here, the call to getinterface is proxied off the
587   // nss thread, not the ui thread as the above comment says. So there is
588   // indeed a chance of mSession going away. bug 615342
589 
590   MOZ_ASSERT(!OnSocketThread(), "on socket thread");
591 
592   nsCOMPtr<nsIInterfaceRequestor> callbacks;
593   {
594     MutexAutoLock lock(mCallbacksLock);
595     callbacks = mCallbacks;
596   }
597   if (callbacks) return callbacks->GetInterface(iid, result);
598   return NS_ERROR_NO_INTERFACE;
599 }
600 
SetEvent(nsresult aStatus)601 void HttpConnectionUDP::SetEvent(nsresult aStatus) {
602   switch (aStatus) {
603     case NS_NET_STATUS_RESOLVING_HOST:
604       mBootstrappedTimings.domainLookupStart = TimeStamp::Now();
605       break;
606     case NS_NET_STATUS_RESOLVED_HOST:
607       mBootstrappedTimings.domainLookupEnd = TimeStamp::Now();
608       break;
609     case NS_NET_STATUS_CONNECTING_TO:
610       mBootstrappedTimings.connectStart = TimeStamp::Now();
611       break;
612     case NS_NET_STATUS_CONNECTED_TO:
613       mBootstrappedTimings.connectEnd = TimeStamp::Now();
614       break;
615     case NS_NET_STATUS_TLS_HANDSHAKE_STARTING:
616       mBootstrappedTimings.secureConnectionStart = TimeStamp::Now();
617       break;
618     case NS_NET_STATUS_TLS_HANDSHAKE_ENDED:
619       mBootstrappedTimings.connectEnd = TimeStamp::Now();
620       break;
621     default:
622       break;
623   }
624 }
625 
IsProxyConnectInProgress()626 bool HttpConnectionUDP::IsProxyConnectInProgress() { return false; }
627 
LastTransactionExpectedNoContent()628 bool HttpConnectionUDP::LastTransactionExpectedNoContent() {
629   return mLastTransactionExpectedNoContent;
630 }
631 
SetLastTransactionExpectedNoContent(bool val)632 void HttpConnectionUDP::SetLastTransactionExpectedNoContent(bool val) {
633   mLastTransactionExpectedNoContent = val;
634 }
635 
IsPersistent()636 bool HttpConnectionUDP::IsPersistent() { return !mDontReuse; }
637 
Transaction()638 nsAHttpTransaction* HttpConnectionUDP::Transaction() { return mHttp3Session; }
639 
BytesWritten()640 int64_t HttpConnectionUDP::BytesWritten() {
641   if (!mHttp3Session) {
642     return 0;
643   }
644   return mHttp3Session->GetBytesWritten();
645 }
646 
OnPacketReceived(nsIUDPSocket * aSocket)647 NS_IMETHODIMP HttpConnectionUDP::OnPacketReceived(nsIUDPSocket* aSocket) {
648   RecvData();
649   return NS_OK;
650 }
651 
OnStopListening(nsIUDPSocket * aSocket,nsresult aStatus)652 NS_IMETHODIMP HttpConnectionUDP::OnStopListening(nsIUDPSocket* aSocket,
653                                                  nsresult aStatus) {
654   CloseTransaction(mHttp3Session, aStatus);
655   return NS_OK;
656 }
657 
GetSelfAddr(NetAddr * addr)658 nsresult HttpConnectionUDP::GetSelfAddr(NetAddr* addr) {
659   if (mSelfAddr) {
660     return mSelfAddr->GetNetAddr(addr);
661   }
662   return NS_ERROR_FAILURE;
663 }
664 
GetPeerAddr(NetAddr * addr)665 nsresult HttpConnectionUDP::GetPeerAddr(NetAddr* addr) {
666   if (mPeerAddr) {
667     return mPeerAddr->GetNetAddr(addr);
668   }
669   return NS_ERROR_FAILURE;
670 }
671 
ResolvedByTRR()672 bool HttpConnectionUDP::ResolvedByTRR() { return mResolvedByTRR; }
673 
674 }  // namespace net
675 }  // namespace mozilla
676