1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 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 #include "MDNSResponderOperator.h" 7 #include "MDNSResponderReply.h" 8 #include "mozilla/EndianUtils.h" 9 #include "mozilla/Logging.h" 10 #include "mozilla/ScopeExit.h" 11 #include "mozilla/Unused.h" 12 #include "nsComponentManagerUtils.h" 13 #include "nsCOMPtr.h" 14 #include "nsDebug.h" 15 #include "nsDNSServiceInfo.h" 16 #include "nsHashPropertyBag.h" 17 #include "nsIProperty.h" 18 #include "nsISimpleEnumerator.h" 19 #include "nsIVariant.h" 20 #include "nsServiceManagerUtils.h" 21 #include "nsNetAddr.h" 22 #include "nsNetCID.h" 23 #include "nsSocketTransportService2.h" 24 #include "nsThreadUtils.h" 25 #include "nsXPCOMCID.h" 26 #include "private/pprio.h" 27 28 #include "nsASocketHandler.h" 29 30 namespace mozilla { 31 namespace net { 32 33 static LazyLogModule gMDNSLog("MDNSResponderOperator"); 34 #undef LOG_I 35 #define LOG_I(...) \ 36 MOZ_LOG(mozilla::net::gMDNSLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) 37 #undef LOG_E 38 #define LOG_E(...) \ 39 MOZ_LOG(mozilla::net::gMDNSLog, mozilla::LogLevel::Error, (__VA_ARGS__)) 40 41 class MDNSResponderOperator::ServiceWatcher final : public nsASocketHandler { 42 public: 43 NS_DECL_THREADSAFE_ISUPPORTS 44 45 // nsASocketHandler methods 46 virtual void OnSocketReady(PRFileDesc* fd, int16_t outFlags) override { 47 MOZ_ASSERT(OnSocketThread(), "not on socket thread"); 48 MOZ_ASSERT(fd == mFD); 49 50 if (outFlags & (PR_POLL_ERR | PR_POLL_HUP | PR_POLL_NVAL)) { 51 LOG_E("error polling on listening socket (%p)", fd); 52 mCondition = NS_ERROR_UNEXPECTED; 53 } 54 55 if (!(outFlags & PR_POLL_READ)) { 56 return; 57 } 58 59 DNSServiceProcessResult(mService); 60 } 61 62 virtual void OnSocketDetached(PRFileDesc* fd) override { 63 MOZ_ASSERT(OnSocketThread(), "not on socket thread"); 64 MOZ_ASSERT(mThread); 65 MOZ_ASSERT(fd == mFD); 66 67 if (!mFD) { 68 return; 69 } 70 71 // Bug 1175387: do not double close the handle here. 72 PR_ChangeFileDescNativeHandle(mFD, -1); 73 PR_Close(mFD); 74 mFD = nullptr; 75 76 mThread->Dispatch( 77 NewRunnableMethod("MDNSResponderOperator::ServiceWatcher::Deallocate", 78 this, &ServiceWatcher::Deallocate), 79 NS_DISPATCH_NORMAL); 80 } 81 82 virtual void IsLocal(bool* aIsLocal) override { *aIsLocal = true; } 83 84 virtual void KeepWhenOffline(bool* aKeepWhenOffline) override { 85 *aKeepWhenOffline = true; 86 } 87 88 virtual uint64_t ByteCountSent() override { return 0; } 89 virtual uint64_t ByteCountReceived() override { return 0; } 90 91 explicit ServiceWatcher(DNSServiceRef aService, 92 MDNSResponderOperator* aOperator) 93 : mThread(nullptr), 94 mSts(nullptr), 95 mOperatorHolder(aOperator), 96 mService(aService), 97 mFD(nullptr), 98 mAttached(false) { 99 if (!gSocketTransportService) { 100 nsCOMPtr<nsISocketTransportService> sts = 101 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID); 102 } 103 } 104 105 nsresult Init() { 106 MOZ_ASSERT(!OnSocketThread(), "on socket thread"); 107 mThread = NS_GetCurrentThread(); 108 109 if (!mService) { 110 return NS_OK; 111 } 112 113 if (!gSocketTransportService) { 114 return NS_ERROR_FAILURE; 115 } 116 mSts = gSocketTransportService; 117 118 int osfd = DNSServiceRefSockFD(mService); 119 if (osfd == -1) { 120 return NS_ERROR_FAILURE; 121 } 122 123 mFD = PR_ImportFile(osfd); 124 return PostEvent("MDNSResponderOperator::ServiceWatcher::OnMsgAttach", 125 &ServiceWatcher::OnMsgAttach); 126 } 127 128 void Close() { 129 MOZ_ASSERT(!OnSocketThread(), "on socket thread"); 130 131 if (!gSocketTransportService) { 132 Deallocate(); 133 return; 134 } 135 136 PostEvent("MDNSResponderOperator::ServiceWatcher::OnMsgClose", 137 &ServiceWatcher::OnMsgClose); 138 } 139 140 private: 141 ~ServiceWatcher() = default; 142 143 void Deallocate() { 144 if (mService) { 145 DNSServiceRefDeallocate(mService); 146 mService = nullptr; 147 } 148 mOperatorHolder = nullptr; 149 } 150 151 nsresult PostEvent(const char* aName, void (ServiceWatcher::*func)(void)) { 152 return gSocketTransportService->Dispatch( 153 NewRunnableMethod(aName, this, func), NS_DISPATCH_NORMAL); 154 } 155 156 void OnMsgClose() { 157 MOZ_ASSERT(OnSocketThread(), "not on socket thread"); 158 159 if (NS_FAILED(mCondition)) { 160 return; 161 } 162 163 // tear down socket. this signals the STS to detach our socket handler. 164 mCondition = NS_BINDING_ABORTED; 165 166 // if we are attached, then socket transport service will call our 167 // OnSocketDetached method automatically. Otherwise, we have to call it 168 // (and thus close the socket) manually. 169 if (!mAttached) { 170 OnSocketDetached(mFD); 171 } 172 } 173 174 void OnMsgAttach() { 175 MOZ_ASSERT(OnSocketThread(), "not on socket thread"); 176 177 if (NS_FAILED(mCondition)) { 178 return; 179 } 180 181 mCondition = TryAttach(); 182 183 // if we hit an error while trying to attach then bail... 184 if (NS_FAILED(mCondition)) { 185 NS_ASSERTION(!mAttached, "should not be attached already"); 186 OnSocketDetached(mFD); 187 } 188 } 189 190 nsresult TryAttach() { 191 MOZ_ASSERT(OnSocketThread(), "not on socket thread"); 192 193 nsresult rv; 194 195 if (!gSocketTransportService) { 196 return NS_ERROR_FAILURE; 197 } 198 199 // 200 // find out if it is going to be ok to attach another socket to the STS. 201 // if not then we have to wait for the STS to tell us that it is ok. 202 // the notification is asynchronous, which means that when we could be 203 // in a race to call AttachSocket once notified. for this reason, when 204 // we get notified, we just re-enter this function. as a result, we are 205 // sure to ask again before calling AttachSocket. in this way we deal 206 // with the race condition. though it isn't the most elegant solution, 207 // it is far simpler than trying to build a system that would guarantee 208 // FIFO ordering (which wouldn't even be that valuable IMO). see bug 209 // 194402 for more info. 210 // 211 if (!gSocketTransportService->CanAttachSocket()) { 212 nsCOMPtr<nsIRunnable> event = NewRunnableMethod( 213 "MDNSResponderOperator::ServiceWatcher::OnMsgAttach", this, 214 &ServiceWatcher::OnMsgAttach); 215 216 nsresult rv = gSocketTransportService->NotifyWhenCanAttachSocket(event); 217 if (NS_FAILED(rv)) { 218 return rv; 219 } 220 } 221 222 // 223 // ok, we can now attach our socket to the STS for polling 224 // 225 rv = gSocketTransportService->AttachSocket(mFD, this); 226 if (NS_FAILED(rv)) { 227 return rv; 228 } 229 230 mAttached = true; 231 232 // 233 // now, configure our poll flags for listening... 234 // 235 mPollFlags = (PR_POLL_READ | PR_POLL_EXCEPT); 236 237 return NS_OK; 238 } 239 240 nsCOMPtr<nsIThread> mThread; 241 RefPtr<nsSocketTransportService> mSts; 242 RefPtr<MDNSResponderOperator> mOperatorHolder; 243 DNSServiceRef mService; 244 PRFileDesc* mFD; 245 bool mAttached; 246 }; 247 248 NS_IMPL_ISUPPORTS(MDNSResponderOperator::ServiceWatcher, nsISupports) 249 250 MDNSResponderOperator::MDNSResponderOperator() 251 : mService(nullptr), 252 mWatcher(nullptr), 253 mThread(NS_GetCurrentThread()), 254 mIsCancelled(false) {} 255 256 MDNSResponderOperator::~MDNSResponderOperator() { Stop(); } 257 258 nsresult MDNSResponderOperator::Start() { 259 if (mIsCancelled) { 260 return NS_OK; 261 } 262 263 if (IsServing()) { 264 Stop(); 265 } 266 267 return NS_OK; 268 } 269 270 nsresult MDNSResponderOperator::Stop() { return ResetService(nullptr); } 271 272 nsresult MDNSResponderOperator::ResetService(DNSServiceRef aService) { 273 nsresult rv; 274 275 if (aService != mService) { 276 if (mWatcher) { 277 mWatcher->Close(); 278 mWatcher = nullptr; 279 } 280 281 if (aService) { 282 RefPtr<ServiceWatcher> watcher = new ServiceWatcher(aService, this); 283 if (NS_WARN_IF(NS_FAILED(rv = watcher->Init()))) { 284 return rv; 285 } 286 mWatcher = watcher; 287 } 288 289 mService = aService; 290 } 291 return NS_OK; 292 } 293 294 BrowseOperator::BrowseOperator(const nsACString& aServiceType, 295 nsIDNSServiceDiscoveryListener* aListener) 296 : MDNSResponderOperator(), 297 mServiceType(aServiceType), 298 mListener(aListener) {} 299 300 nsresult BrowseOperator::Start() { 301 nsresult rv; 302 if (NS_WARN_IF(NS_FAILED(rv = MDNSResponderOperator::Start()))) { 303 return rv; 304 } 305 306 DNSServiceRef service = nullptr; 307 DNSServiceErrorType err = DNSServiceBrowse( 308 &service, 0, kDNSServiceInterfaceIndexAny, mServiceType.get(), nullptr, 309 &BrowseReplyRunnable::Reply, this); 310 NS_WARNING_ASSERTION(kDNSServiceErr_NoError == err, "DNSServiceBrowse fail"); 311 312 if (mListener) { 313 if (kDNSServiceErr_NoError == err) { 314 mListener->OnDiscoveryStarted(mServiceType); 315 } else { 316 mListener->OnStartDiscoveryFailed(mServiceType, err); 317 } 318 } 319 320 if (NS_WARN_IF(kDNSServiceErr_NoError != err)) { 321 return NS_ERROR_FAILURE; 322 } 323 324 return ResetService(service); 325 } 326 327 nsresult BrowseOperator::Stop() { 328 bool isServing = IsServing(); 329 nsresult rv = MDNSResponderOperator::Stop(); 330 331 if (isServing && mListener) { 332 if (NS_SUCCEEDED(rv)) { 333 mListener->OnDiscoveryStopped(mServiceType); 334 } else { 335 mListener->OnStopDiscoveryFailed(mServiceType, static_cast<uint32_t>(rv)); 336 } 337 } 338 339 return rv; 340 } 341 342 void BrowseOperator::Reply(DNSServiceRef aSdRef, DNSServiceFlags aFlags, 343 uint32_t aInterfaceIndex, 344 DNSServiceErrorType aErrorCode, 345 const nsACString& aServiceName, 346 const nsACString& aRegType, 347 const nsACString& aReplyDomain) { 348 MOZ_ASSERT(GetThread() == NS_GetCurrentThread()); 349 350 if (NS_WARN_IF(kDNSServiceErr_NoError != aErrorCode)) { 351 LOG_E("BrowseOperator::Reply (%d)", aErrorCode); 352 if (mListener) { 353 mListener->OnStartDiscoveryFailed(mServiceType, aErrorCode); 354 } 355 return; 356 } 357 358 if (!mListener) { 359 return; 360 } 361 nsCOMPtr<nsIDNSServiceInfo> info = new nsDNSServiceInfo(); 362 363 if (NS_WARN_IF(!info)) { 364 return; 365 } 366 if (NS_WARN_IF(NS_FAILED(info->SetServiceName(aServiceName)))) { 367 return; 368 } 369 if (NS_WARN_IF(NS_FAILED(info->SetServiceType(aRegType)))) { 370 return; 371 } 372 if (NS_WARN_IF(NS_FAILED(info->SetDomainName(aReplyDomain)))) { 373 return; 374 } 375 376 if (aFlags & kDNSServiceFlagsAdd) { 377 mListener->OnServiceFound(info); 378 } else { 379 mListener->OnServiceLost(info); 380 } 381 } 382 383 RegisterOperator::RegisterOperator(nsIDNSServiceInfo* aServiceInfo, 384 nsIDNSRegistrationListener* aListener) 385 : MDNSResponderOperator(), 386 mServiceInfo(aServiceInfo), 387 mListener(aListener) {} 388 389 nsresult RegisterOperator::Start() { 390 nsresult rv; 391 392 rv = MDNSResponderOperator::Start(); 393 if (NS_WARN_IF(NS_FAILED(rv))) { 394 return rv; 395 } 396 uint16_t port; 397 if (NS_WARN_IF(NS_FAILED(rv = mServiceInfo->GetPort(&port)))) { 398 return rv; 399 } 400 nsAutoCString type; 401 if (NS_WARN_IF(NS_FAILED(rv = mServiceInfo->GetServiceType(type)))) { 402 return rv; 403 } 404 405 TXTRecordRef txtRecord; 406 char buf[TXT_BUFFER_SIZE] = {0}; 407 TXTRecordCreate(&txtRecord, TXT_BUFFER_SIZE, buf); 408 409 nsCOMPtr<nsIPropertyBag2> attributes; 410 if (NS_FAILED(rv = mServiceInfo->GetAttributes(getter_AddRefs(attributes)))) { 411 LOG_I("register: no attributes"); 412 } else { 413 nsCOMPtr<nsISimpleEnumerator> enumerator; 414 if (NS_WARN_IF(NS_FAILED( 415 rv = attributes->GetEnumerator(getter_AddRefs(enumerator))))) { 416 return rv; 417 } 418 419 bool hasMoreElements; 420 while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreElements)) && 421 hasMoreElements) { 422 nsCOMPtr<nsISupports> element; 423 MOZ_ALWAYS_SUCCEEDS(enumerator->GetNext(getter_AddRefs(element))); 424 nsCOMPtr<nsIProperty> property = do_QueryInterface(element); 425 MOZ_ASSERT(property); 426 427 nsAutoString name; 428 nsCOMPtr<nsIVariant> value; 429 MOZ_ALWAYS_SUCCEEDS(property->GetName(name)); 430 MOZ_ALWAYS_SUCCEEDS(property->GetValue(getter_AddRefs(value))); 431 432 nsAutoCString str; 433 if (NS_WARN_IF(NS_FAILED(value->GetAsACString(str)))) { 434 continue; 435 } 436 437 TXTRecordSetValue(&txtRecord, 438 /* it's safe because key name is ASCII only. */ 439 NS_LossyConvertUTF16toASCII(name).get(), str.Length(), 440 str.get()); 441 } 442 } 443 444 nsAutoCString host; 445 nsAutoCString name; 446 nsAutoCString domain; 447 448 DNSServiceRef service = nullptr; 449 DNSServiceErrorType err = DNSServiceRegister( 450 &service, 0, 0, 451 NS_SUCCEEDED(mServiceInfo->GetServiceName(name)) ? name.get() : nullptr, 452 type.get(), 453 NS_SUCCEEDED(mServiceInfo->GetDomainName(domain)) ? domain.get() 454 : nullptr, 455 NS_SUCCEEDED(mServiceInfo->GetHost(host)) ? host.get() : nullptr, 456 NativeEndian::swapToNetworkOrder(port), TXTRecordGetLength(&txtRecord), 457 TXTRecordGetBytesPtr(&txtRecord), &RegisterReplyRunnable::Reply, this); 458 NS_WARNING_ASSERTION(kDNSServiceErr_NoError == err, 459 "DNSServiceRegister fail"); 460 461 TXTRecordDeallocate(&txtRecord); 462 463 if (NS_WARN_IF(kDNSServiceErr_NoError != err)) { 464 if (mListener) { 465 mListener->OnRegistrationFailed(mServiceInfo, err); 466 } 467 return NS_ERROR_FAILURE; 468 } 469 470 return ResetService(service); 471 } 472 473 nsresult RegisterOperator::Stop() { 474 bool isServing = IsServing(); 475 nsresult rv = MDNSResponderOperator::Stop(); 476 477 if (isServing && mListener) { 478 if (NS_SUCCEEDED(rv)) { 479 mListener->OnServiceUnregistered(mServiceInfo); 480 } else { 481 mListener->OnUnregistrationFailed(mServiceInfo, 482 static_cast<uint32_t>(rv)); 483 } 484 } 485 486 return rv; 487 } 488 489 void RegisterOperator::Reply(DNSServiceRef aSdRef, DNSServiceFlags aFlags, 490 DNSServiceErrorType aErrorCode, 491 const nsACString& aName, 492 const nsACString& aRegType, 493 const nsACString& aDomain) { 494 MOZ_ASSERT(GetThread() == NS_GetCurrentThread()); 495 496 if (kDNSServiceErr_NoError != aErrorCode) { 497 LOG_E("RegisterOperator::Reply (%d)", aErrorCode); 498 } 499 500 if (!mListener) { 501 return; 502 } 503 nsCOMPtr<nsIDNSServiceInfo> info = new nsDNSServiceInfo(mServiceInfo); 504 if (NS_WARN_IF(NS_FAILED(info->SetServiceName(aName)))) { 505 return; 506 } 507 if (NS_WARN_IF(NS_FAILED(info->SetServiceType(aRegType)))) { 508 return; 509 } 510 if (NS_WARN_IF(NS_FAILED(info->SetDomainName(aDomain)))) { 511 return; 512 } 513 514 if (kDNSServiceErr_NoError == aErrorCode) { 515 if (aFlags & kDNSServiceFlagsAdd) { 516 mListener->OnServiceRegistered(info); 517 } else { 518 // If a successfully-registered name later suffers a name conflict 519 // or similar problem and has to be deregistered, the callback will 520 // be invoked with the kDNSServiceFlagsAdd flag not set. 521 LOG_E("RegisterOperator::Reply: deregister"); 522 if (NS_WARN_IF(NS_FAILED(Stop()))) { 523 return; 524 } 525 } 526 } else { 527 mListener->OnRegistrationFailed(info, aErrorCode); 528 } 529 } 530 531 ResolveOperator::ResolveOperator(nsIDNSServiceInfo* aServiceInfo, 532 nsIDNSServiceResolveListener* aListener) 533 : MDNSResponderOperator(), 534 mServiceInfo(aServiceInfo), 535 mListener(aListener) {} 536 537 nsresult ResolveOperator::Start() { 538 nsresult rv; 539 if (NS_WARN_IF(NS_FAILED(rv = MDNSResponderOperator::Start()))) { 540 return rv; 541 } 542 543 nsAutoCString name; 544 mServiceInfo->GetServiceName(name); 545 nsAutoCString type; 546 mServiceInfo->GetServiceType(type); 547 nsAutoCString domain; 548 mServiceInfo->GetDomainName(domain); 549 550 LOG_I("Resolve: (%s), (%s), (%s)", name.get(), type.get(), domain.get()); 551 552 DNSServiceRef service = nullptr; 553 DNSServiceErrorType err = DNSServiceResolve( 554 &service, 0, kDNSServiceInterfaceIndexAny, name.get(), type.get(), 555 domain.get(), (DNSServiceResolveReply)&ResolveReplyRunnable::Reply, this); 556 557 if (NS_WARN_IF(kDNSServiceErr_NoError != err)) { 558 if (mListener) { 559 mListener->OnResolveFailed(mServiceInfo, err); 560 } 561 return NS_ERROR_FAILURE; 562 } 563 564 return ResetService(service); 565 } 566 567 void ResolveOperator::Reply(DNSServiceRef aSdRef, DNSServiceFlags aFlags, 568 uint32_t aInterfaceIndex, 569 DNSServiceErrorType aErrorCode, 570 const nsACString& aFullName, 571 const nsACString& aHostTarget, uint16_t aPort, 572 uint16_t aTxtLen, const unsigned char* aTxtRecord) { 573 MOZ_ASSERT(GetThread() == NS_GetCurrentThread()); 574 575 auto guard = MakeScopeExit([&] { Unused << NS_WARN_IF(NS_FAILED(Stop())); }); 576 577 if (NS_WARN_IF(kDNSServiceErr_NoError != aErrorCode)) { 578 LOG_E("ResolveOperator::Reply (%d)", aErrorCode); 579 return; 580 } 581 582 // Resolve TXT record 583 int count = TXTRecordGetCount(aTxtLen, aTxtRecord); 584 LOG_I("resolve: txt count = %d, len = %d", count, aTxtLen); 585 nsCOMPtr<nsIWritablePropertyBag2> attributes = new nsHashPropertyBag(); 586 if (NS_WARN_IF(!attributes)) { 587 return; 588 } 589 if (count) { 590 for (int i = 0; i < count; ++i) { 591 char key[TXT_BUFFER_SIZE] = {'\0'}; 592 uint8_t vSize = 0; 593 const void* value = nullptr; 594 if (kDNSServiceErr_NoError != 595 TXTRecordGetItemAtIndex(aTxtLen, aTxtRecord, i, TXT_BUFFER_SIZE, key, 596 &vSize, &value)) { 597 break; 598 } 599 600 nsAutoCString str(reinterpret_cast<const char*>(value), vSize); 601 LOG_I("resolve TXT: (%d) %s=%s", vSize, key, str.get()); 602 603 if (NS_WARN_IF(NS_FAILED(attributes->SetPropertyAsACString( 604 /* it's safe to convert because key name is ASCII only. */ 605 NS_ConvertASCIItoUTF16(key), str)))) { 606 break; 607 } 608 } 609 } 610 611 if (!mListener) { 612 return; 613 } 614 nsCOMPtr<nsIDNSServiceInfo> info = new nsDNSServiceInfo(mServiceInfo); 615 if (NS_WARN_IF(NS_FAILED(info->SetHost(aHostTarget)))) { 616 return; 617 } 618 if (NS_WARN_IF(NS_FAILED(info->SetPort(aPort)))) { 619 return; 620 } 621 if (NS_WARN_IF(NS_FAILED(info->SetAttributes(attributes)))) { 622 return; 623 } 624 625 if (kDNSServiceErr_NoError == aErrorCode) { 626 GetAddrInfor(info); 627 } else { 628 mListener->OnResolveFailed(info, aErrorCode); 629 Unused << NS_WARN_IF(NS_FAILED(Stop())); 630 } 631 } 632 633 void ResolveOperator::GetAddrInfor(nsIDNSServiceInfo* aServiceInfo) { 634 RefPtr<GetAddrInfoOperator> getAddreOp = 635 new GetAddrInfoOperator(aServiceInfo, mListener); 636 Unused << NS_WARN_IF(NS_FAILED(getAddreOp->Start())); 637 } 638 639 GetAddrInfoOperator::GetAddrInfoOperator( 640 nsIDNSServiceInfo* aServiceInfo, nsIDNSServiceResolveListener* aListener) 641 : MDNSResponderOperator(), 642 mServiceInfo(aServiceInfo), 643 mListener(aListener) {} 644 645 nsresult GetAddrInfoOperator::Start() { 646 nsresult rv; 647 if (NS_WARN_IF(NS_FAILED(rv = MDNSResponderOperator::Start()))) { 648 return rv; 649 } 650 651 nsAutoCString host; 652 mServiceInfo->GetHost(host); 653 654 LOG_I("GetAddrInfo: (%s)", host.get()); 655 656 DNSServiceRef service = nullptr; 657 DNSServiceErrorType err = DNSServiceGetAddrInfo( 658 &service, kDNSServiceFlagsForceMulticast, kDNSServiceInterfaceIndexAny, 659 kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6, host.get(), 660 (DNSServiceGetAddrInfoReply)&GetAddrInfoReplyRunnable::Reply, this); 661 662 if (NS_WARN_IF(kDNSServiceErr_NoError != err)) { 663 if (mListener) { 664 mListener->OnResolveFailed(mServiceInfo, err); 665 } 666 return NS_ERROR_FAILURE; 667 } 668 669 return ResetService(service); 670 } 671 672 void GetAddrInfoOperator::Reply(DNSServiceRef aSdRef, DNSServiceFlags aFlags, 673 uint32_t aInterfaceIndex, 674 DNSServiceErrorType aErrorCode, 675 const nsACString& aHostName, 676 const NetAddr& aAddress, uint32_t aTTL) { 677 MOZ_ASSERT(GetThread() == NS_GetCurrentThread()); 678 679 auto guard = MakeScopeExit([&] { Unused << NS_WARN_IF(NS_FAILED(Stop())); }); 680 681 if (NS_WARN_IF(kDNSServiceErr_NoError != aErrorCode)) { 682 LOG_E("GetAddrInfoOperator::Reply (%d)", aErrorCode); 683 return; 684 } 685 686 if (!mListener) { 687 return; 688 } 689 690 NetAddr addr = aAddress; 691 nsCOMPtr<nsINetAddr> address = new nsNetAddr(&addr); 692 nsCString addressStr; 693 if (NS_WARN_IF(NS_FAILED(address->GetAddress(addressStr)))) { 694 return; 695 } 696 697 nsCOMPtr<nsIDNSServiceInfo> info = new nsDNSServiceInfo(mServiceInfo); 698 if (NS_WARN_IF(NS_FAILED(info->SetAddress(addressStr)))) { 699 return; 700 } 701 702 /** 703 * |kDNSServiceFlagsMoreComing| means this callback will be one or more 704 * callback events later, so this instance should be kept alive until all 705 * follow-up events are processed. 706 */ 707 if (aFlags & kDNSServiceFlagsMoreComing) { 708 guard.release(); 709 } 710 711 if (kDNSServiceErr_NoError == aErrorCode) { 712 mListener->OnServiceResolved(info); 713 } else { 714 mListener->OnResolveFailed(info, aErrorCode); 715 } 716 } 717 718 } // namespace net 719 } // namespace mozilla 720