Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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 : #include "mozilla/dom/FlyWebService.h"
8 : #include "mozilla/ClearOnShutdown.h"
9 : #include "mozilla/StaticPtr.h"
10 : #include "mozilla/ScopeExit.h"
11 : #include "mozilla/dom/Promise.h"
12 : #include "mozilla/dom/FlyWebPublishedServerIPC.h"
13 : #include "mozilla/AddonPathService.h"
14 : #include "nsISocketTransportService.h"
15 : #include "mdns/libmdns/nsDNSServiceInfo.h"
16 : #include "nsIUUIDGenerator.h"
17 : #include "nsStandardURL.h"
18 : #include "mozilla/Services.h"
19 : #include "nsISupportsPrimitives.h"
20 : #include "mozilla/dom/FlyWebDiscoveryManagerBinding.h"
21 : #include "prnetdb.h"
22 : #include "DNS.h"
23 : #include "nsContentPermissionHelper.h"
24 : #include "nsSocketTransportService2.h"
25 : #include "nsSocketTransport2.h"
26 : #include "nsHashPropertyBag.h"
27 : #include "nsNetUtil.h"
28 : #include "nsISimpleEnumerator.h"
29 : #include "nsIProperty.h"
30 : #include "nsICertOverrideService.h"
31 :
32 : namespace mozilla {
33 : namespace dom {
34 :
35 : struct FlyWebPublishOptions;
36 :
37 : static LazyLogModule gFlyWebServiceLog("FlyWebService");
38 : #undef LOG_I
39 : #define LOG_I(...) MOZ_LOG(mozilla::dom::gFlyWebServiceLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
40 :
41 : #undef LOG_E
42 : #define LOG_E(...) MOZ_LOG(mozilla::dom::gFlyWebServiceLog, mozilla::LogLevel::Error, (__VA_ARGS__))
43 :
44 : #undef LOG_TEST_I
45 : #define LOG_TEST_I(...) MOZ_LOG_TEST(mozilla::dom::gFlyWebServiceLog, mozilla::LogLevel::Debug)
46 :
47 : class FlyWebPublishServerPermissionCheck final
48 : : public nsIContentPermissionRequest
49 : , public nsIRunnable
50 : {
51 : public:
52 : NS_DECL_ISUPPORTS
53 :
54 0 : FlyWebPublishServerPermissionCheck(const nsCString& aServiceName, uint64_t aWindowID,
55 : FlyWebPublishedServer* aServer)
56 0 : : mServiceName(aServiceName)
57 : , mWindowID(aWindowID)
58 0 : , mServer(aServer)
59 0 : {}
60 :
61 : uint64_t WindowID() const
62 : {
63 : return mWindowID;
64 : }
65 :
66 0 : NS_IMETHOD Run() override
67 : {
68 0 : MOZ_ASSERT(NS_IsMainThread());
69 :
70 0 : nsGlobalWindow* globalWindow = nsGlobalWindow::GetInnerWindowWithId(mWindowID);
71 0 : if (!globalWindow) {
72 0 : return Cancel();
73 : }
74 0 : mWindow = globalWindow->AsInner();
75 0 : if (NS_WARN_IF(!mWindow)) {
76 0 : return Cancel();
77 : }
78 :
79 0 : nsCOMPtr<nsIDocument> doc = mWindow->GetDoc();
80 0 : if (NS_WARN_IF(!doc)) {
81 0 : return Cancel();
82 : }
83 :
84 0 : mPrincipal = doc->NodePrincipal();
85 0 : MOZ_ASSERT(mPrincipal);
86 :
87 0 : mRequester = new nsContentPermissionRequester(mWindow);
88 0 : return nsContentPermissionUtils::AskPermission(this, mWindow);
89 : }
90 :
91 0 : NS_IMETHOD Cancel() override
92 : {
93 0 : Resolve(false);
94 0 : return NS_OK;
95 : }
96 :
97 0 : NS_IMETHOD Allow(JS::HandleValue aChoices) override
98 : {
99 0 : MOZ_ASSERT(aChoices.isUndefined());
100 0 : Resolve(true);
101 0 : return NS_OK;
102 : }
103 :
104 0 : NS_IMETHOD GetTypes(nsIArray** aTypes) override
105 : {
106 0 : nsTArray<nsString> emptyOptions;
107 0 : return nsContentPermissionUtils::CreatePermissionArray(NS_LITERAL_CSTRING("flyweb-publish-server"),
108 0 : NS_LITERAL_CSTRING("unused"), emptyOptions, aTypes);
109 : }
110 :
111 0 : NS_IMETHOD GetRequester(nsIContentPermissionRequester** aRequester) override
112 : {
113 0 : NS_ENSURE_ARG_POINTER(aRequester);
114 0 : nsCOMPtr<nsIContentPermissionRequester> requester = mRequester;
115 0 : requester.forget(aRequester);
116 0 : return NS_OK;
117 : }
118 :
119 0 : NS_IMETHOD GetPrincipal(nsIPrincipal** aRequestingPrincipal) override
120 : {
121 0 : NS_IF_ADDREF(*aRequestingPrincipal = mPrincipal);
122 0 : return NS_OK;
123 : }
124 :
125 0 : NS_IMETHOD GetWindow(mozIDOMWindow** aRequestingWindow) override
126 : {
127 0 : NS_IF_ADDREF(*aRequestingWindow = mWindow);
128 0 : return NS_OK;
129 : }
130 :
131 0 : NS_IMETHOD GetElement(nsIDOMElement** aRequestingElement) override
132 : {
133 0 : *aRequestingElement = nullptr;
134 0 : return NS_OK;
135 : }
136 :
137 : private:
138 0 : void Resolve(bool aResolve)
139 : {
140 0 : mServer->PermissionGranted(aResolve);
141 0 : }
142 :
143 0 : virtual ~FlyWebPublishServerPermissionCheck() = default;
144 :
145 : nsCString mServiceName;
146 : uint64_t mWindowID;
147 : RefPtr<FlyWebPublishedServer> mServer;
148 : nsCOMPtr<nsPIDOMWindowInner> mWindow;
149 : nsCOMPtr<nsIPrincipal> mPrincipal;
150 : nsCOMPtr<nsIContentPermissionRequester> mRequester;
151 : };
152 :
153 0 : NS_IMPL_ISUPPORTS(FlyWebPublishServerPermissionCheck,
154 : nsIContentPermissionRequest,
155 : nsIRunnable)
156 :
157 : class FlyWebMDNSService final
158 : : public nsIDNSServiceDiscoveryListener
159 : , public nsIDNSServiceResolveListener
160 : , public nsIDNSRegistrationListener
161 : , public nsITimerCallback
162 : {
163 : friend class FlyWebService;
164 :
165 : private:
166 : enum DiscoveryState {
167 : DISCOVERY_IDLE,
168 : DISCOVERY_STARTING,
169 : DISCOVERY_RUNNING,
170 : DISCOVERY_STOPPING
171 : };
172 :
173 : public:
174 : NS_DECL_ISUPPORTS
175 : NS_DECL_NSIDNSSERVICEDISCOVERYLISTENER
176 : NS_DECL_NSIDNSSERVICERESOLVELISTENER
177 : NS_DECL_NSIDNSREGISTRATIONLISTENER
178 : NS_DECL_NSITIMERCALLBACK
179 :
180 : explicit FlyWebMDNSService(FlyWebService* aService,
181 : const nsACString& aServiceType);
182 :
183 : private:
184 0 : virtual ~FlyWebMDNSService() = default;
185 :
186 : nsresult Init();
187 : nsresult StartDiscovery();
188 : nsresult StopDiscovery();
189 :
190 : void ListDiscoveredServices(nsTArray<FlyWebDiscoveredService>& aServices);
191 : bool HasService(const nsAString& aServiceId);
192 : nsresult PairWithService(const nsAString& aServiceId,
193 : UniquePtr<FlyWebService::PairedInfo>& aInfo);
194 :
195 : nsresult StartDiscoveryOf(FlyWebPublishedServerImpl* aServer);
196 :
197 : void EnsureDiscoveryStarted();
198 : void EnsureDiscoveryStopped();
199 :
200 : // Cycle-breaking link to manager.
201 : FlyWebService* mService;
202 : nsCString mServiceType;
203 :
204 : // Indicates the desired state of the system. If mDiscoveryActive is true,
205 : // it indicates that backend discovery "should be happening", and discovery
206 : // events should be forwarded to listeners.
207 : // If false, the backend discovery "should be idle", and any discovery events
208 : // that show up should not be forwarded to listeners.
209 : bool mDiscoveryActive;
210 :
211 : uint32_t mNumConsecutiveStartDiscoveryFailures;
212 :
213 : // Represents the internal discovery state as it relates to nsDNSServiceDiscovery.
214 : // When mDiscoveryActive is true, this state will periodically loop from
215 : // (IDLE => STARTING => RUNNING => STOPPING => IDLE).
216 : DiscoveryState mDiscoveryState;
217 :
218 : nsCOMPtr<nsITimer> mDiscoveryStartTimer;
219 : nsCOMPtr<nsITimer> mDiscoveryStopTimer;
220 : nsCOMPtr<nsIDNSServiceDiscovery> mDNSServiceDiscovery;
221 : nsCOMPtr<nsICancelable> mCancelDiscovery;
222 : nsTHashtable<nsStringHashKey> mNewServiceSet;
223 :
224 0 : struct DiscoveredInfo
225 : {
226 : explicit DiscoveredInfo(nsIDNSServiceInfo* aDNSServiceInfo);
227 : FlyWebDiscoveredService mService;
228 : nsCOMPtr<nsIDNSServiceInfo> mDNSServiceInfo;
229 : };
230 : nsClassHashtable<nsStringHashKey, DiscoveredInfo> mServiceMap;
231 : };
232 :
233 : void
234 0 : LogDNSInfo(nsIDNSServiceInfo* aServiceInfo, const char* aFunc)
235 : {
236 0 : if (!LOG_TEST_I()) {
237 0 : return;
238 : }
239 :
240 0 : nsCString tmp;
241 0 : aServiceInfo->GetServiceName(tmp);
242 0 : LOG_I("%s: serviceName=%s", aFunc, tmp.get());
243 :
244 0 : aServiceInfo->GetHost(tmp);
245 0 : LOG_I("%s: host=%s", aFunc, tmp.get());
246 :
247 0 : aServiceInfo->GetAddress(tmp);
248 0 : LOG_I("%s: address=%s", aFunc, tmp.get());
249 :
250 0 : uint16_t port = -2;
251 0 : aServiceInfo->GetPort(&port);
252 0 : LOG_I("%s: port=%d", aFunc, (int)port);
253 :
254 0 : nsCOMPtr<nsIPropertyBag2> attributes;
255 0 : aServiceInfo->GetAttributes(getter_AddRefs(attributes));
256 0 : if (!attributes) {
257 0 : LOG_I("%s: no attributes", aFunc);
258 : } else {
259 0 : nsCOMPtr<nsISimpleEnumerator> enumerator;
260 0 : attributes->GetEnumerator(getter_AddRefs(enumerator));
261 0 : MOZ_ASSERT(enumerator);
262 :
263 0 : LOG_I("%s: attributes start", aFunc);
264 :
265 : bool hasMoreElements;
266 0 : while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreElements)) &&
267 : hasMoreElements) {
268 0 : nsCOMPtr<nsISupports> element;
269 0 : MOZ_ALWAYS_SUCCEEDS(enumerator->GetNext(getter_AddRefs(element)));
270 0 : nsCOMPtr<nsIProperty> property = do_QueryInterface(element);
271 0 : MOZ_ASSERT(property);
272 :
273 0 : nsAutoString name;
274 0 : nsCOMPtr<nsIVariant> value;
275 0 : MOZ_ALWAYS_SUCCEEDS(property->GetName(name));
276 0 : MOZ_ALWAYS_SUCCEEDS(property->GetValue(getter_AddRefs(value)));
277 :
278 0 : nsAutoCString str;
279 0 : nsresult rv = value->GetAsACString(str);
280 0 : if (NS_SUCCEEDED(rv)) {
281 0 : LOG_I("%s: attribute name=%s value=%s", aFunc,
282 : NS_ConvertUTF16toUTF8(name).get(), str.get());
283 : } else {
284 : uint16_t type;
285 0 : MOZ_ALWAYS_SUCCEEDS(value->GetDataType(&type));
286 0 : LOG_I("%s: attribute *unstringifiable* name=%s type=%d", aFunc,
287 : NS_ConvertUTF16toUTF8(name).get(), (int)type);
288 : }
289 : }
290 :
291 0 : LOG_I("%s: attributes end", aFunc);
292 : }
293 : }
294 :
295 0 : NS_IMPL_ISUPPORTS(FlyWebMDNSService,
296 : nsIDNSServiceDiscoveryListener,
297 : nsIDNSServiceResolveListener,
298 : nsIDNSRegistrationListener,
299 : nsITimerCallback)
300 :
301 0 : FlyWebMDNSService::FlyWebMDNSService(
302 : FlyWebService* aService,
303 0 : const nsACString& aServiceType)
304 : : mService(aService)
305 : , mServiceType(aServiceType)
306 : , mDiscoveryActive(false)
307 : , mNumConsecutiveStartDiscoveryFailures(0)
308 0 : , mDiscoveryState(DISCOVERY_IDLE)
309 0 : {}
310 :
311 : nsresult
312 0 : FlyWebMDNSService::OnDiscoveryStarted(const nsACString& aServiceType)
313 : {
314 0 : MOZ_ASSERT(mDiscoveryState == DISCOVERY_STARTING);
315 0 : mDiscoveryState = DISCOVERY_RUNNING;
316 : // Reset consecutive start discovery failures.
317 0 : mNumConsecutiveStartDiscoveryFailures = 0;
318 0 : LOG_I("===========================================");
319 0 : LOG_I("MDNSService::OnDiscoveryStarted(%s)", PromiseFlatCString(aServiceType).get());
320 0 : LOG_I("===========================================");
321 :
322 : // Clear the new service array.
323 0 : mNewServiceSet.Clear();
324 :
325 : // If service discovery is inactive, then stop network discovery immediately.
326 0 : if (!mDiscoveryActive) {
327 : // Set the stop timer to fire immediately.
328 0 : Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStopTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT)));
329 0 : return NS_OK;
330 : }
331 :
332 : // Otherwise, set the stop timer to fire in 5 seconds.
333 0 : Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStopTimer->InitWithCallback(this, 5 * 1000, nsITimer::TYPE_ONE_SHOT)));
334 :
335 0 : return NS_OK;
336 : }
337 :
338 : nsresult
339 0 : FlyWebMDNSService::OnDiscoveryStopped(const nsACString& aServiceType)
340 : {
341 0 : LOG_I("///////////////////////////////////////////");
342 0 : LOG_I("MDNSService::OnDiscoveryStopped(%s)", PromiseFlatCString(aServiceType).get());
343 0 : LOG_I("///////////////////////////////////////////");
344 0 : MOZ_ASSERT(mDiscoveryState == DISCOVERY_STOPPING);
345 0 : mDiscoveryState = DISCOVERY_IDLE;
346 :
347 : // If service discovery is inactive, then discard all results and do not proceed.
348 0 : if (!mDiscoveryActive) {
349 0 : mServiceMap.Clear();
350 0 : mNewServiceSet.Clear();
351 0 : return NS_OK;
352 : }
353 :
354 : // Process the service map, add to the pair map.
355 0 : for (auto iter = mServiceMap.Iter(); !iter.Done(); iter.Next()) {
356 0 : DiscoveredInfo* service = iter.UserData();
357 :
358 0 : if (!mNewServiceSet.Contains(service->mService.mServiceId)) {
359 0 : iter.Remove();
360 : }
361 : }
362 :
363 : // Notify FlyWebService of changed service list.
364 0 : mService->NotifyDiscoveredServicesChanged();
365 :
366 : // Start discovery again immediately.
367 0 : Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStartTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT)));
368 :
369 0 : return NS_OK;
370 : }
371 :
372 : nsresult
373 0 : FlyWebMDNSService::OnServiceFound(nsIDNSServiceInfo* aServiceInfo)
374 : {
375 0 : LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnServiceFound");
376 :
377 : // If discovery is not active, don't do anything with the result.
378 : // If there is no discovery underway, ignore this.
379 0 : if (!mDiscoveryActive || mDiscoveryState != DISCOVERY_RUNNING) {
380 0 : return NS_OK;
381 : }
382 :
383 : // Discovery is underway - resolve the service.
384 0 : nsresult rv = mDNSServiceDiscovery->ResolveService(aServiceInfo, this);
385 0 : NS_ENSURE_SUCCESS(rv, rv);
386 :
387 0 : return NS_OK;
388 : }
389 :
390 : nsresult
391 0 : FlyWebMDNSService::OnServiceLost(nsIDNSServiceInfo* aServiceInfo)
392 : {
393 0 : LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnServiceLost");
394 :
395 0 : return NS_OK;
396 : }
397 :
398 : nsresult
399 0 : FlyWebMDNSService::OnStartDiscoveryFailed(const nsACString& aServiceType, int32_t aErrorCode)
400 : {
401 0 : LOG_E("MDNSService::OnStartDiscoveryFailed(%s): %d", PromiseFlatCString(aServiceType).get(), (int) aErrorCode);
402 :
403 0 : MOZ_ASSERT(mDiscoveryState == DISCOVERY_STARTING);
404 0 : mDiscoveryState = DISCOVERY_IDLE;
405 0 : mNumConsecutiveStartDiscoveryFailures++;
406 :
407 : // If discovery is active, and the number of consecutive failures is < 3, try starting again.
408 0 : if (mDiscoveryActive && mNumConsecutiveStartDiscoveryFailures < 3) {
409 0 : Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStartTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT)));
410 : }
411 :
412 0 : return NS_OK;
413 : }
414 :
415 : nsresult
416 0 : FlyWebMDNSService::OnStopDiscoveryFailed(const nsACString& aServiceType, int32_t aErrorCode)
417 : {
418 0 : LOG_E("MDNSService::OnStopDiscoveryFailed(%s)", PromiseFlatCString(aServiceType).get());
419 0 : MOZ_ASSERT(mDiscoveryState == DISCOVERY_STOPPING);
420 0 : mDiscoveryState = DISCOVERY_IDLE;
421 :
422 : // If discovery is active, start discovery again immediately.
423 0 : if (mDiscoveryActive) {
424 0 : Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStartTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT)));
425 : }
426 :
427 0 : return NS_OK;
428 : }
429 :
430 : static bool
431 0 : IsAcceptableServiceAddress(const nsCString& addr)
432 : {
433 : PRNetAddr prNetAddr;
434 0 : PRStatus status = PR_StringToNetAddr(addr.get(), &prNetAddr);
435 0 : if (status == PR_FAILURE) {
436 0 : return false;
437 : }
438 : // Only allow ipv4 addreses for now.
439 0 : return prNetAddr.raw.family == PR_AF_INET;
440 : }
441 :
442 : nsresult
443 0 : FlyWebMDNSService::OnServiceResolved(nsIDNSServiceInfo* aServiceInfo)
444 : {
445 0 : LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnServiceResolved");
446 :
447 : // If discovery is not active, don't do anything with the result.
448 : // If there is no discovery underway, ignore this resolve.
449 0 : if (!mDiscoveryActive || mDiscoveryState != DISCOVERY_RUNNING) {
450 0 : return NS_OK;
451 : }
452 :
453 : nsresult rv;
454 :
455 0 : nsCString address;
456 0 : rv = aServiceInfo->GetAddress(address);
457 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
458 0 : return rv;
459 : }
460 :
461 0 : if (!IsAcceptableServiceAddress(address)) {
462 0 : return NS_OK;
463 : }
464 :
465 : // Create a new serviceInfo and stuff it in the new service array.
466 0 : UniquePtr<DiscoveredInfo> svc(new DiscoveredInfo(aServiceInfo));
467 0 : mNewServiceSet.PutEntry(svc->mService.mServiceId);
468 :
469 : DiscoveredInfo* existingSvc =
470 0 : mServiceMap.Get(svc->mService.mServiceId);
471 0 : if (existingSvc) {
472 : // Update the underlying DNS service info, but leave the old object in place.
473 0 : existingSvc->mDNSServiceInfo = aServiceInfo;
474 : } else {
475 0 : DiscoveredInfo* info = svc.release();
476 0 : mServiceMap.Put(info->mService.mServiceId, info);
477 : }
478 :
479 : // Notify FlyWebService of changed service list.
480 0 : mService->NotifyDiscoveredServicesChanged();
481 :
482 0 : return NS_OK;
483 : }
484 :
485 0 : FlyWebMDNSService::DiscoveredInfo::DiscoveredInfo(nsIDNSServiceInfo* aDNSServiceInfo)
486 0 : : mDNSServiceInfo(aDNSServiceInfo)
487 : {
488 0 : nsCString tmp;
489 0 : DebugOnly<nsresult> drv = aDNSServiceInfo->GetServiceName(tmp);
490 0 : MOZ_ASSERT(NS_SUCCEEDED(drv));
491 0 : CopyUTF8toUTF16(tmp, mService.mDisplayName);
492 :
493 0 : mService.mTransport = NS_LITERAL_STRING("mdns");
494 :
495 0 : drv = aDNSServiceInfo->GetServiceType(tmp);
496 0 : MOZ_ASSERT(NS_SUCCEEDED(drv));
497 0 : CopyUTF8toUTF16(tmp, mService.mServiceType);
498 :
499 0 : nsCOMPtr<nsIPropertyBag2> attrs;
500 0 : drv = aDNSServiceInfo->GetAttributes(getter_AddRefs(attrs));
501 0 : MOZ_ASSERT(NS_SUCCEEDED(drv));
502 0 : if (attrs) {
503 0 : attrs->GetPropertyAsAString(NS_LITERAL_STRING("cert"), mService.mCert);
504 0 : attrs->GetPropertyAsAString(NS_LITERAL_STRING("path"), mService.mPath);
505 : }
506 :
507 : // Construct a service id from the name, host, address, and port.
508 0 : nsCString cHost;
509 0 : drv = aDNSServiceInfo->GetHost(cHost);
510 0 : MOZ_ASSERT(NS_SUCCEEDED(drv));
511 :
512 0 : nsCString cAddress;
513 0 : drv = aDNSServiceInfo->GetAddress(cAddress);
514 0 : MOZ_ASSERT(NS_SUCCEEDED(drv));
515 :
516 : uint16_t port;
517 0 : drv = aDNSServiceInfo->GetPort(&port);
518 0 : MOZ_ASSERT(NS_SUCCEEDED(drv));
519 0 : nsAutoString portStr;
520 0 : portStr.AppendInt(port, 10);
521 :
522 : mService.mServiceId =
523 0 : NS_ConvertUTF8toUTF16(cAddress) +
524 0 : NS_LITERAL_STRING(":") +
525 0 : portStr +
526 0 : NS_LITERAL_STRING("|") +
527 0 : mService.mServiceType +
528 0 : NS_LITERAL_STRING("|") +
529 0 : NS_ConvertUTF8toUTF16(cHost) +
530 0 : NS_LITERAL_STRING("|") +
531 0 : mService.mDisplayName;
532 0 : }
533 :
534 :
535 : nsresult
536 0 : FlyWebMDNSService::OnResolveFailed(nsIDNSServiceInfo* aServiceInfo, int32_t aErrorCode)
537 : {
538 0 : LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnResolveFailed");
539 :
540 0 : return NS_OK;
541 : }
542 :
543 : nsresult
544 0 : FlyWebMDNSService::OnServiceRegistered(nsIDNSServiceInfo* aServiceInfo)
545 : {
546 0 : LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnServiceRegistered");
547 :
548 0 : nsCString cName;
549 0 : if (NS_WARN_IF(NS_FAILED(aServiceInfo->GetServiceName(cName)))) {
550 0 : return NS_ERROR_FAILURE;
551 : }
552 :
553 0 : nsString name = NS_ConvertUTF8toUTF16(cName);
554 : RefPtr<FlyWebPublishedServer> existingServer =
555 0 : FlyWebService::GetOrCreate()->FindPublishedServerByName(name);
556 0 : if (!existingServer) {
557 0 : return NS_ERROR_FAILURE;
558 : }
559 :
560 0 : existingServer->PublishedServerStarted(NS_OK);
561 :
562 0 : return NS_OK;
563 : }
564 :
565 : nsresult
566 0 : FlyWebMDNSService::OnServiceUnregistered(nsIDNSServiceInfo* aServiceInfo)
567 : {
568 0 : LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnServiceUnregistered");
569 :
570 0 : nsCString cName;
571 0 : if (NS_WARN_IF(NS_FAILED(aServiceInfo->GetServiceName(cName)))) {
572 0 : return NS_ERROR_FAILURE;
573 : }
574 :
575 0 : nsString name = NS_ConvertUTF8toUTF16(cName);
576 : RefPtr<FlyWebPublishedServer> existingServer =
577 0 : FlyWebService::GetOrCreate()->FindPublishedServerByName(name);
578 0 : if (!existingServer) {
579 0 : return NS_ERROR_FAILURE;
580 : }
581 :
582 0 : LOG_I("OnServiceRegistered(MDNS): De-advertised server with name %s.", cName.get());
583 :
584 0 : return NS_OK;
585 : }
586 :
587 : nsresult
588 0 : FlyWebMDNSService::OnRegistrationFailed(nsIDNSServiceInfo* aServiceInfo, int32_t errorCode)
589 : {
590 0 : LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnRegistrationFailed");
591 :
592 0 : nsCString cName;
593 0 : if (NS_WARN_IF(NS_FAILED(aServiceInfo->GetServiceName(cName)))) {
594 0 : return NS_ERROR_FAILURE;
595 : }
596 :
597 0 : nsString name = NS_ConvertUTF8toUTF16(cName);
598 : RefPtr<FlyWebPublishedServer> existingServer =
599 0 : FlyWebService::GetOrCreate()->FindPublishedServerByName(name);
600 0 : if (!existingServer) {
601 0 : return NS_ERROR_FAILURE;
602 : }
603 :
604 0 : LOG_I("OnServiceRegistered(MDNS): Registration of server with name %s failed.", cName.get());
605 :
606 : // Remove the nsICancelable from the published server.
607 0 : existingServer->PublishedServerStarted(NS_ERROR_FAILURE);
608 0 : return NS_OK;
609 : }
610 :
611 : nsresult
612 0 : FlyWebMDNSService::OnUnregistrationFailed(nsIDNSServiceInfo* aServiceInfo, int32_t errorCode)
613 : {
614 0 : LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnUnregistrationFailed");
615 :
616 0 : nsCString cName;
617 0 : if (NS_WARN_IF(NS_FAILED(aServiceInfo->GetServiceName(cName)))) {
618 0 : return NS_ERROR_FAILURE;
619 : }
620 :
621 0 : nsString name = NS_ConvertUTF8toUTF16(cName);
622 : RefPtr<FlyWebPublishedServer> existingServer =
623 0 : FlyWebService::GetOrCreate()->FindPublishedServerByName(name);
624 0 : if (!existingServer) {
625 0 : return NS_ERROR_FAILURE;
626 : }
627 :
628 0 : LOG_I("OnServiceRegistered(MDNS): Un-Advertisement of server with name %s failed.", cName.get());
629 0 : return NS_OK;
630 : }
631 :
632 : nsresult
633 0 : FlyWebMDNSService::Notify(nsITimer* timer)
634 : {
635 0 : if (timer == mDiscoveryStopTimer.get()) {
636 0 : LOG_I("MDNSService::Notify() got discovery stop timeout");
637 : // Internet discovery stop timer has fired.
638 0 : nsresult rv = StopDiscovery();
639 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
640 0 : return rv;
641 : }
642 0 : return NS_OK;
643 : }
644 :
645 0 : if (timer == mDiscoveryStartTimer.get()) {
646 0 : LOG_I("MDNSService::Notify() got discovery start timeout");
647 : // Internet discovery start timer has fired.
648 0 : nsresult rv = StartDiscovery();
649 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
650 0 : return rv;
651 : }
652 0 : return NS_OK;
653 : }
654 :
655 0 : LOG_E("MDNSService::Notify got unknown timeout.");
656 0 : return NS_OK;
657 : }
658 :
659 : nsresult
660 0 : FlyWebMDNSService::Init()
661 : {
662 0 : MOZ_ASSERT(mDiscoveryState == DISCOVERY_IDLE);
663 :
664 0 : mDiscoveryStartTimer = do_CreateInstance("@mozilla.org/timer;1");
665 0 : if (!mDiscoveryStartTimer) {
666 0 : return NS_ERROR_FAILURE;
667 : }
668 :
669 0 : mDiscoveryStopTimer = do_CreateInstance("@mozilla.org/timer;1");
670 0 : if (!mDiscoveryStopTimer) {
671 0 : return NS_ERROR_FAILURE;
672 : }
673 :
674 : nsresult rv;
675 0 : mDNSServiceDiscovery = do_GetService(DNSSERVICEDISCOVERY_CONTRACT_ID, &rv);
676 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
677 0 : return rv;
678 : }
679 :
680 0 : return NS_OK;
681 : }
682 :
683 : nsresult
684 0 : FlyWebMDNSService::StartDiscovery()
685 : {
686 : nsresult rv;
687 :
688 : // Always cancel the timer.
689 0 : rv = mDiscoveryStartTimer->Cancel();
690 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
691 0 : LOG_E("FlyWeb failed to cancel DNS service discovery start timer.");
692 : }
693 :
694 : // If discovery is not idle, don't start it.
695 0 : if (mDiscoveryState != DISCOVERY_IDLE) {
696 0 : return NS_OK;
697 : }
698 :
699 0 : LOG_I("FlyWeb starting dicovery.");
700 0 : mDiscoveryState = DISCOVERY_STARTING;
701 :
702 : // start the discovery.
703 0 : rv = mDNSServiceDiscovery->StartDiscovery(mServiceType, this,
704 0 : getter_AddRefs(mCancelDiscovery));
705 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
706 0 : LOG_E("FlyWeb failed to start DNS service discovery.");
707 0 : return rv;
708 : }
709 :
710 0 : return NS_OK;
711 : }
712 :
713 : nsresult
714 0 : FlyWebMDNSService::StopDiscovery()
715 : {
716 : nsresult rv;
717 :
718 : // Always cancel the timer.
719 0 : rv = mDiscoveryStopTimer->Cancel();
720 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
721 0 : LOG_E("FlyWeb failed to cancel DNS service discovery stop timer.");
722 : }
723 :
724 : // If discovery is not running, do nothing.
725 0 : if (mDiscoveryState != DISCOVERY_RUNNING) {
726 0 : return NS_OK;
727 : }
728 :
729 0 : LOG_I("FlyWeb stopping dicovery.");
730 :
731 : // Mark service discovery as stopping.
732 0 : mDiscoveryState = DISCOVERY_STOPPING;
733 :
734 0 : if (mCancelDiscovery) {
735 0 : LOG_I("MDNSService::StopDiscovery() - mCancelDiscovery exists!");
736 0 : nsCOMPtr<nsICancelable> cancelDiscovery = mCancelDiscovery.forget();
737 0 : rv = cancelDiscovery->Cancel(NS_ERROR_ABORT);
738 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
739 0 : LOG_E("FlyWeb failed to cancel DNS stop service discovery.");
740 : }
741 : } else {
742 0 : LOG_I("MDNSService::StopDiscovery() - mCancelDiscovery does not exist!");
743 0 : mDiscoveryState = DISCOVERY_IDLE;
744 : }
745 :
746 0 : return NS_OK;
747 : }
748 :
749 : void
750 0 : FlyWebMDNSService::ListDiscoveredServices(nsTArray<FlyWebDiscoveredService>& aServices)
751 : {
752 0 : for (auto iter = mServiceMap.Iter(); !iter.Done(); iter.Next()) {
753 0 : aServices.AppendElement(iter.UserData()->mService);
754 : }
755 0 : }
756 :
757 : bool
758 0 : FlyWebMDNSService::HasService(const nsAString& aServiceId)
759 : {
760 0 : return mServiceMap.Contains(aServiceId);
761 : }
762 :
763 : nsresult
764 0 : FlyWebMDNSService::PairWithService(const nsAString& aServiceId,
765 : UniquePtr<FlyWebService::PairedInfo>& aInfo)
766 : {
767 0 : MOZ_ASSERT(HasService(aServiceId));
768 :
769 : nsresult rv;
770 : nsCOMPtr<nsIUUIDGenerator> uuidgen =
771 0 : do_GetService("@mozilla.org/uuid-generator;1", &rv);
772 0 : NS_ENSURE_SUCCESS(rv, rv);
773 :
774 : nsID id;
775 0 : rv = uuidgen->GenerateUUIDInPlace(&id);
776 0 : NS_ENSURE_SUCCESS(rv, rv);
777 :
778 0 : aInfo.reset(new FlyWebService::PairedInfo());
779 :
780 : char uuidChars[NSID_LENGTH];
781 0 : id.ToProvidedString(uuidChars);
782 0 : CopyUTF8toUTF16(Substring(uuidChars + 1, uuidChars + NSID_LENGTH - 2),
783 0 : aInfo->mService.mHostname);
784 :
785 0 : DiscoveredInfo* discInfo = mServiceMap.Get(aServiceId);
786 :
787 0 : nsAutoString url;
788 0 : if (discInfo->mService.mCert.IsEmpty()) {
789 0 : url.AssignLiteral("http://");
790 : } else {
791 0 : url.AssignLiteral("https://");
792 : }
793 0 : url.Append(aInfo->mService.mHostname);
794 0 : if (!discInfo->mService.mPath.IsEmpty()) {
795 0 : if (discInfo->mService.mPath.Find("/") != 0) {
796 0 : url.Append(NS_LITERAL_STRING("/"));
797 : }
798 0 : url.Append(discInfo->mService.mPath);
799 : } else {
800 0 : url.Append(NS_LITERAL_STRING("/"));
801 : }
802 0 : nsCOMPtr<nsIURI> uiURL;
803 0 : NS_NewURI(getter_AddRefs(uiURL), url);
804 0 : MOZ_ASSERT(uiURL);
805 0 : if (uiURL) {
806 0 : nsAutoCString spec;
807 0 : uiURL->GetSpec(spec);
808 0 : CopyUTF8toUTF16(spec, aInfo->mService.mUiUrl);
809 : }
810 :
811 0 : aInfo->mService.mDiscoveredService = discInfo->mService;
812 0 : aInfo->mDNSServiceInfo = discInfo->mDNSServiceInfo;
813 :
814 0 : return NS_OK;
815 : }
816 :
817 : nsresult
818 0 : FlyWebMDNSService::StartDiscoveryOf(FlyWebPublishedServerImpl* aServer)
819 : {
820 :
821 : RefPtr<FlyWebPublishedServer> existingServer =
822 0 : FlyWebService::GetOrCreate()->FindPublishedServerByName(aServer->Name());
823 0 : MOZ_ASSERT(existingServer);
824 :
825 : // Advertise the service via mdns.
826 0 : RefPtr<net::nsDNSServiceInfo> serviceInfo(new net::nsDNSServiceInfo());
827 :
828 0 : serviceInfo->SetPort(aServer->Port());
829 0 : serviceInfo->SetServiceType(mServiceType);
830 :
831 0 : nsCString certKey;
832 0 : aServer->GetCertKey(certKey);
833 0 : nsString uiURL;
834 0 : aServer->GetUiUrl(uiURL);
835 :
836 0 : if (!uiURL.IsEmpty() || !certKey.IsEmpty()) {
837 0 : RefPtr<nsHashPropertyBag> attrs = new nsHashPropertyBag();
838 0 : if (!uiURL.IsEmpty()) {
839 0 : attrs->SetPropertyAsAString(NS_LITERAL_STRING("path"), uiURL);
840 : }
841 0 : if (!certKey.IsEmpty()) {
842 0 : attrs->SetPropertyAsACString(NS_LITERAL_STRING("cert"), certKey);
843 : }
844 0 : serviceInfo->SetAttributes(attrs);
845 : }
846 :
847 0 : nsCString cstrName = NS_ConvertUTF16toUTF8(aServer->Name());
848 0 : LOG_I("MDNSService::StartDiscoveryOf() advertising service %s", cstrName.get());
849 0 : serviceInfo->SetServiceName(cstrName);
850 :
851 0 : LogDNSInfo(serviceInfo, "FlyWebMDNSService::StartDiscoveryOf");
852 :
853 : // Advertise the service.
854 0 : nsCOMPtr<nsICancelable> cancelRegister;
855 0 : nsresult rv = mDNSServiceDiscovery->
856 0 : RegisterService(serviceInfo, this, getter_AddRefs(cancelRegister));
857 0 : NS_ENSURE_SUCCESS(rv, rv);
858 :
859 : // All done.
860 0 : aServer->SetCancelRegister(cancelRegister);
861 :
862 0 : return NS_OK;
863 : }
864 :
865 : void
866 0 : FlyWebMDNSService::EnsureDiscoveryStarted()
867 : {
868 0 : mDiscoveryActive = true;
869 : // If state is idle, start discovery immediately.
870 0 : if (mDiscoveryState == DISCOVERY_IDLE) {
871 0 : StartDiscovery();
872 : }
873 0 : }
874 :
875 : void
876 0 : FlyWebMDNSService::EnsureDiscoveryStopped()
877 : {
878 : // All we need to do is set the flag to false.
879 : // If current state is IDLE, it's already the correct state.
880 : // Otherwise, the handlers for the internal state
881 : // transitions will check this flag and drive the state
882 : // towards IDLE.
883 0 : mDiscoveryActive = false;
884 0 : }
885 :
886 3 : static StaticRefPtr<FlyWebService> gFlyWebService;
887 :
888 0 : NS_IMPL_ISUPPORTS(FlyWebService, nsIObserver)
889 :
890 0 : FlyWebService::FlyWebService()
891 0 : : mMonitor("FlyWebService::mMonitor")
892 : {
893 0 : MOZ_ASSERT(NS_IsMainThread());
894 0 : nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
895 0 : if (obs) {
896 0 : obs->AddObserver(this, "inner-window-destroyed", false);
897 : }
898 0 : }
899 :
900 0 : FlyWebService::~FlyWebService()
901 : {
902 0 : }
903 :
904 : FlyWebService*
905 3 : FlyWebService::GetExisting()
906 : {
907 3 : return gFlyWebService;
908 : }
909 :
910 : FlyWebService*
911 0 : FlyWebService::GetOrCreate()
912 : {
913 0 : if (!gFlyWebService) {
914 0 : gFlyWebService = new FlyWebService();
915 0 : ClearOnShutdown(&gFlyWebService);
916 0 : ErrorResult rv = gFlyWebService->Init();
917 0 : if (rv.Failed()) {
918 0 : gFlyWebService = nullptr;
919 0 : return nullptr;
920 : }
921 : }
922 0 : return gFlyWebService;
923 : }
924 :
925 : ErrorResult
926 0 : FlyWebService::Init()
927 : {
928 : // Most functions of FlyWebService should not be started in the child.
929 : // Instead FlyWebService in the child is mainly responsible for tracking
930 : // publishedServer lifetimes. Other functions are handled by the
931 : // FlyWebService running in the parent.
932 0 : if (XRE_GetProcessType() == GeckoProcessType_Content) {
933 0 : return ErrorResult(NS_OK);
934 : }
935 :
936 0 : MOZ_ASSERT(NS_IsMainThread());
937 0 : if (!mMDNSHttpService) {
938 0 : mMDNSHttpService = new FlyWebMDNSService(this, NS_LITERAL_CSTRING("_http._tcp."));
939 0 : ErrorResult rv;
940 :
941 0 : rv = mMDNSHttpService->Init();
942 0 : if (rv.Failed()) {
943 0 : LOG_E("FlyWebService failed to initialize MDNS _http._tcp.");
944 0 : mMDNSHttpService = nullptr;
945 0 : rv.SuppressException();
946 : }
947 : }
948 :
949 0 : if (!mMDNSFlywebService) {
950 0 : mMDNSFlywebService = new FlyWebMDNSService(this, NS_LITERAL_CSTRING("_flyweb._tcp."));
951 0 : ErrorResult rv;
952 :
953 0 : rv = mMDNSFlywebService->Init();
954 0 : if (rv.Failed()) {
955 0 : LOG_E("FlyWebService failed to initialize MDNS _flyweb._tcp.");
956 0 : mMDNSFlywebService = nullptr;
957 0 : rv.SuppressException();
958 : }
959 : }
960 :
961 0 : return ErrorResult(NS_OK);
962 : }
963 :
964 : static already_AddRefed<FlyWebPublishPromise>
965 0 : MakeRejectionPromise(const char* name)
966 : {
967 0 : MozPromiseHolder<FlyWebPublishPromise> holder;
968 0 : RefPtr<FlyWebPublishPromise> promise = holder.Ensure(name);
969 0 : holder.Reject(NS_ERROR_FAILURE, name);
970 0 : return promise.forget();
971 : }
972 :
973 : static bool
974 0 : CheckForFlyWebAddon(const nsACString& uriString)
975 : {
976 : // Before proceeding, ensure that the FlyWeb system addon exists.
977 : nsresult rv;
978 0 : nsCOMPtr<nsIURI> uri;
979 0 : rv = NS_NewURI(getter_AddRefs(uri), uriString);
980 0 : if (NS_FAILED(rv)) {
981 0 : return false;
982 : }
983 :
984 0 : JSAddonId *addonId = MapURIToAddonID(uri);
985 0 : if (!addonId) {
986 0 : return false;
987 : }
988 :
989 0 : JSFlatString* flat = JS_ASSERT_STRING_IS_FLAT(JS::StringOfAddonId(addonId));
990 0 : nsAutoString addonIdString;
991 0 : AssignJSFlatString(addonIdString, flat);
992 0 : if (!addonIdString.EqualsLiteral("flyweb@mozilla.org")) {
993 0 : nsCString addonIdCString = NS_ConvertUTF16toUTF8(addonIdString);
994 0 : return false;
995 : }
996 :
997 0 : return true;
998 : }
999 :
1000 : already_AddRefed<FlyWebPublishPromise>
1001 0 : FlyWebService::PublishServer(const nsAString& aName,
1002 : const FlyWebPublishOptions& aOptions,
1003 : nsPIDOMWindowInner* aWindow)
1004 : {
1005 : // Scan uiUrl for illegal characters
1006 :
1007 : RefPtr<FlyWebPublishedServer> existingServer =
1008 0 : FlyWebService::GetOrCreate()->FindPublishedServerByName(aName);
1009 0 : if (existingServer) {
1010 0 : LOG_I("PublishServer: Trying to publish server with already-existing name %s.",
1011 : NS_ConvertUTF16toUTF8(aName).get());
1012 0 : return MakeRejectionPromise(__func__);
1013 : }
1014 :
1015 0 : RefPtr<FlyWebPublishedServer> server;
1016 0 : if (XRE_GetProcessType() == GeckoProcessType_Content) {
1017 0 : server = new FlyWebPublishedServerChild(aWindow, aName, aOptions);
1018 : } else {
1019 0 : server = new FlyWebPublishedServerImpl(aWindow, aName, aOptions);
1020 :
1021 : // Before proceeding, ensure that the FlyWeb system addon exists.
1022 0 : if (!CheckForFlyWebAddon(NS_LITERAL_CSTRING("chrome://flyweb/skin/icon-64.png")) &&
1023 0 : !CheckForFlyWebAddon(NS_LITERAL_CSTRING("chrome://flyweb/content/icon-64.png")))
1024 : {
1025 0 : LOG_E("PublishServer: Failed to find FlyWeb system addon.");
1026 0 : return MakeRejectionPromise(__func__);
1027 : }
1028 : }
1029 :
1030 0 : if (aWindow) {
1031 : nsresult rv;
1032 :
1033 0 : MOZ_ASSERT(NS_IsMainThread());
1034 0 : rv = NS_DispatchToCurrentThread(
1035 0 : MakeAndAddRef<FlyWebPublishServerPermissionCheck>(
1036 0 : NS_ConvertUTF16toUTF8(aName), aWindow->WindowID(), server));
1037 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
1038 0 : LOG_E("PublishServer: Failed to dispatch permission check runnable for %s",
1039 : NS_ConvertUTF16toUTF8(aName).get());
1040 0 : return MakeRejectionPromise(__func__);
1041 : }
1042 : } else {
1043 : // If aWindow is null, we're definitely in the e10s parent process.
1044 : // In this case, we know that permission has already been granted
1045 : // by the user because of content-process prompt.
1046 0 : MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
1047 0 : server->PermissionGranted(true);
1048 : }
1049 :
1050 0 : mServers.AppendElement(server);
1051 :
1052 0 : return server->GetPublishPromise();
1053 : }
1054 :
1055 : already_AddRefed<FlyWebPublishedServer>
1056 0 : FlyWebService::FindPublishedServerByName(
1057 : const nsAString& aName)
1058 : {
1059 0 : MOZ_ASSERT(NS_IsMainThread());
1060 0 : for (FlyWebPublishedServer* publishedServer : mServers) {
1061 0 : if (publishedServer->Name().Equals(aName)) {
1062 0 : RefPtr<FlyWebPublishedServer> server = publishedServer;
1063 0 : return server.forget();
1064 : }
1065 : }
1066 0 : return nullptr;
1067 : }
1068 :
1069 : void
1070 0 : FlyWebService::RegisterDiscoveryManager(FlyWebDiscoveryManager* aDiscoveryManager)
1071 : {
1072 0 : MOZ_ASSERT(NS_IsMainThread());
1073 0 : mDiscoveryManagerTable.PutEntry(aDiscoveryManager);
1074 0 : if (mMDNSHttpService) {
1075 0 : mMDNSHttpService->EnsureDiscoveryStarted();
1076 : }
1077 0 : if (mMDNSFlywebService) {
1078 0 : mMDNSFlywebService->EnsureDiscoveryStarted();
1079 : }
1080 0 : }
1081 :
1082 : void
1083 0 : FlyWebService::UnregisterDiscoveryManager(FlyWebDiscoveryManager* aDiscoveryManager)
1084 : {
1085 0 : MOZ_ASSERT(NS_IsMainThread());
1086 0 : mDiscoveryManagerTable.RemoveEntry(aDiscoveryManager);
1087 0 : if (mDiscoveryManagerTable.IsEmpty()) {
1088 0 : if (mMDNSHttpService) {
1089 0 : mMDNSHttpService->EnsureDiscoveryStopped();
1090 : }
1091 0 : if (mMDNSFlywebService) {
1092 0 : mMDNSFlywebService->EnsureDiscoveryStopped();
1093 : }
1094 : }
1095 0 : }
1096 :
1097 : NS_IMETHODIMP
1098 0 : FlyWebService::Observe(nsISupports* aSubject, const char* aTopic,
1099 : const char16_t* aData)
1100 : {
1101 0 : MOZ_ASSERT(NS_IsMainThread());
1102 0 : if (strcmp(aTopic, "inner-window-destroyed")) {
1103 0 : return NS_OK;
1104 : }
1105 :
1106 0 : nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
1107 0 : NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE);
1108 :
1109 : uint64_t innerID;
1110 0 : nsresult rv = wrapper->GetData(&innerID);
1111 0 : NS_ENSURE_SUCCESS(rv, rv);
1112 :
1113 : // Make a copy of mServers to iterate over, because closing a server
1114 : // can remove entries from mServers.
1115 0 : nsCOMArray<FlyWebPublishedServer> serversCopy;
1116 0 : for (FlyWebPublishedServer* server : mServers) {
1117 0 : serversCopy.AppendElement(server);
1118 : }
1119 :
1120 0 : for (FlyWebPublishedServer* server : serversCopy) {
1121 0 : if (server->OwnerWindowID() == innerID) {
1122 0 : server->Close();
1123 : }
1124 : }
1125 :
1126 0 : return NS_OK;
1127 : }
1128 :
1129 : void
1130 0 : FlyWebService::UnregisterServer(FlyWebPublishedServer* aServer)
1131 : {
1132 0 : MOZ_ASSERT(NS_IsMainThread());
1133 0 : DebugOnly<bool> removed = mServers.RemoveElement(aServer);
1134 0 : MOZ_ASSERT(removed);
1135 0 : }
1136 :
1137 : bool
1138 0 : FlyWebService::HasConnectionOrServer(uint64_t aWindowID)
1139 : {
1140 0 : MOZ_ASSERT(NS_IsMainThread());
1141 0 : for (FlyWebPublishedServer* server : mServers) {
1142 0 : nsPIDOMWindowInner* win = server->GetOwner();
1143 0 : if (win && win->WindowID() == aWindowID) {
1144 0 : return true;
1145 : }
1146 : }
1147 :
1148 0 : return false;
1149 : }
1150 :
1151 : void
1152 0 : FlyWebService::NotifyDiscoveredServicesChanged()
1153 : {
1154 : // Process the service map, add to the pair map.
1155 0 : for (auto iter = mDiscoveryManagerTable.Iter(); !iter.Done(); iter.Next()) {
1156 0 : iter.Get()->GetKey()->NotifyDiscoveredServicesChanged();
1157 : }
1158 0 : }
1159 :
1160 : void
1161 0 : FlyWebService::ListDiscoveredServices(nsTArray<FlyWebDiscoveredService>& aServices)
1162 : {
1163 0 : MOZ_ASSERT(NS_IsMainThread());
1164 0 : if (mMDNSHttpService) {
1165 0 : mMDNSHttpService->ListDiscoveredServices(aServices);
1166 : }
1167 0 : if (mMDNSFlywebService) {
1168 0 : mMDNSFlywebService->ListDiscoveredServices(aServices);
1169 : }
1170 0 : }
1171 :
1172 : void
1173 0 : FlyWebService::PairWithService(const nsAString& aServiceId,
1174 : FlyWebPairingCallback& aCallback)
1175 : {
1176 0 : MOZ_ASSERT(NS_IsMainThread());
1177 : // See if we have already paired with this service. If so, re-use the
1178 : // FlyWebPairedService for that.
1179 : {
1180 0 : ReentrantMonitorAutoEnter pairedMapLock(mMonitor);
1181 0 : for (auto iter = mPairedServiceTable.Iter(); !iter.Done(); iter.Next()) {
1182 0 : PairedInfo* pairInfo = iter.UserData();
1183 0 : if (pairInfo->mService.mDiscoveredService.mServiceId.Equals(aServiceId)) {
1184 0 : ErrorResult er;
1185 0 : ReentrantMonitorAutoExit pairedMapRelease(mMonitor);
1186 0 : aCallback.PairingSucceeded(pairInfo->mService, er);
1187 0 : ENSURE_SUCCESS_VOID(er);
1188 0 : return;
1189 : }
1190 : }
1191 : }
1192 :
1193 0 : UniquePtr<PairedInfo> pairInfo;
1194 :
1195 0 : nsresult rv = NS_OK;
1196 0 : bool notFound = false;
1197 0 : if (mMDNSHttpService && mMDNSHttpService->HasService(aServiceId)) {
1198 0 : rv = mMDNSHttpService->PairWithService(aServiceId, pairInfo);
1199 0 : } else if (mMDNSFlywebService && mMDNSFlywebService->HasService(aServiceId)) {
1200 0 : rv = mMDNSFlywebService->PairWithService(aServiceId, pairInfo);
1201 : } else {
1202 0 : notFound = true;
1203 : }
1204 :
1205 0 : if (NS_FAILED(rv)) {
1206 0 : ErrorResult result;
1207 0 : result.ThrowWithCustomCleanup(rv);
1208 0 : const nsAString& reason = NS_LITERAL_STRING("Error pairing.");
1209 0 : aCallback.PairingFailed(reason, result);
1210 0 : ENSURE_SUCCESS_VOID(result);
1211 0 : return;
1212 : }
1213 :
1214 0 : if (!pairInfo) {
1215 0 : ErrorResult res;
1216 : const nsAString& reason = notFound ?
1217 0 : NS_LITERAL_STRING("No such service.") :
1218 0 : NS_LITERAL_STRING("Error pairing.");
1219 0 : aCallback.PairingFailed(reason, res);
1220 0 : ENSURE_SUCCESS_VOID(res);
1221 0 : return;
1222 : }
1223 :
1224 : // Add fingerprint to certificate override database.
1225 0 : if (!pairInfo->mService.mDiscoveredService.mCert.IsEmpty()) {
1226 : nsCOMPtr<nsICertOverrideService> override =
1227 0 : do_GetService("@mozilla.org/security/certoverride;1");
1228 0 : if (!override ||
1229 0 : NS_FAILED(override->RememberTemporaryValidityOverrideUsingFingerprint(
1230 : NS_ConvertUTF16toUTF8(pairInfo->mService.mHostname),
1231 : -1,
1232 : NS_ConvertUTF16toUTF8(pairInfo->mService.mDiscoveredService.mCert),
1233 : nsICertOverrideService::ERROR_UNTRUSTED |
1234 : nsICertOverrideService::ERROR_MISMATCH))) {
1235 0 : ErrorResult res;
1236 0 : aCallback.PairingFailed(NS_LITERAL_STRING("Error adding certificate override."), res);
1237 0 : ENSURE_SUCCESS_VOID(res);
1238 0 : return;
1239 : }
1240 : }
1241 :
1242 : // Grab a weak reference to the PairedInfo so that we can
1243 : // use it even after ownership has been transferred to mPairedServiceTable
1244 0 : PairedInfo* pairInfoWeak = pairInfo.release();
1245 :
1246 : {
1247 0 : ReentrantMonitorAutoEnter pairedMapLock(mMonitor);
1248 0 : mPairedServiceTable.Put(
1249 0 : NS_ConvertUTF16toUTF8(pairInfoWeak->mService.mHostname), pairInfoWeak);
1250 : }
1251 :
1252 0 : ErrorResult er;
1253 0 : aCallback.PairingSucceeded(pairInfoWeak->mService, er);
1254 0 : ENSURE_SUCCESS_VOID(er);
1255 : }
1256 :
1257 : nsresult
1258 0 : FlyWebService::CreateTransportForHost(const char **types,
1259 : uint32_t typeCount,
1260 : const nsACString &host,
1261 : int32_t port,
1262 : const nsACString &hostRoute,
1263 : int32_t portRoute,
1264 : nsIProxyInfo *proxyInfo,
1265 : nsISocketTransport **result)
1266 : {
1267 : // This might be called on background threads
1268 :
1269 0 : *result = nullptr;
1270 :
1271 0 : nsCString ipAddrString;
1272 : uint16_t discPort;
1273 :
1274 : {
1275 0 : ReentrantMonitorAutoEnter pairedMapLock(mMonitor);
1276 :
1277 0 : PairedInfo* info = mPairedServiceTable.Get(host);
1278 :
1279 0 : if (!info) {
1280 0 : return NS_OK;
1281 : }
1282 :
1283 : // Get the ip address of the underlying service.
1284 0 : info->mDNSServiceInfo->GetAddress(ipAddrString);
1285 0 : info->mDNSServiceInfo->GetPort(&discPort);
1286 : }
1287 :
1288 : // Parse it into an NetAddr.
1289 : PRNetAddr prNetAddr;
1290 0 : PRStatus status = PR_StringToNetAddr(ipAddrString.get(), &prNetAddr);
1291 0 : NS_ENSURE_FALSE(status == PR_FAILURE, NS_ERROR_FAILURE);
1292 :
1293 : // Convert PRNetAddr to NetAddr.
1294 : mozilla::net::NetAddr netAddr;
1295 0 : PRNetAddrToNetAddr(&prNetAddr, &netAddr);
1296 0 : netAddr.inet.port = htons(discPort);
1297 :
1298 0 : RefPtr<mozilla::net::nsSocketTransport> trans = new mozilla::net::nsSocketTransport();
1299 0 : nsresult rv = trans->InitPreResolved(
1300 0 : types, typeCount, host, port, hostRoute, portRoute, proxyInfo, &netAddr);
1301 0 : NS_ENSURE_SUCCESS(rv, rv);
1302 :
1303 0 : trans.forget(result);
1304 0 : return NS_OK;
1305 : }
1306 :
1307 : void
1308 0 : FlyWebService::StartDiscoveryOf(FlyWebPublishedServerImpl* aServer)
1309 : {
1310 0 : MOZ_ASSERT(NS_IsMainThread());
1311 0 : nsresult rv = mMDNSFlywebService ?
1312 0 : mMDNSFlywebService->StartDiscoveryOf(aServer) :
1313 0 : NS_ERROR_FAILURE;
1314 :
1315 0 : if (NS_FAILED(rv)) {
1316 0 : aServer->PublishedServerStarted(rv);
1317 : }
1318 0 : }
1319 :
1320 : } // namespace dom
1321 : } // namespace mozilla
|