1################################################################################ 2# 3# Copyright (c) 2007-2008 Christopher J. Stawarz 4# 5# Permission is hereby granted, free of charge, to any person 6# obtaining a copy of this software and associated documentation files 7# (the "Software"), to deal in the Software without restriction, 8# including without limitation the rights to use, copy, modify, merge, 9# publish, distribute, sublicense, and/or sell copies of the Software, 10# and to permit persons to whom the Software is furnished to do so, 11# subject to the following conditions: 12# 13# The above copyright notice and this permission notice shall be 14# included in all copies or substantial portions of the Software. 15# 16# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 20# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 21# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23# SOFTWARE. 24# 25################################################################################ 26 27 28 29""" 30 31Pure-Python interface to Apple Bonjour and compatible DNS-SD libraries 32 33pybonjour provides a pure-Python interface (via ctypes) to Apple 34Bonjour and compatible DNS-SD libraries (such as Avahi). It allows 35Python scripts to take advantage of Zero Configuration Networking 36(Zeroconf) to register, discover, and resolve services on both local 37and wide-area networks. Since pybonjour is implemented in pure 38Python, scripts that use it can easily be ported to Mac OS X, Windows, 39Linux, and other systems that run Bonjour. 40 41Note on strings: Internally, all strings used in DNS-SD are UTF-8 42strings. String arguments passed to the DNS-SD functions provided by 43pybonjour must be either unicode instances or str instances that can 44be converted to unicode using the default encoding. (Passing a 45non-convertible str will result in an exception.) Strings returned 46from pybonjour (either directly from API functions or passed to 47application callbacks) are always unicode instances. 48 49""" 50 51 52__author__ = 'Christopher Stawarz <cstawarz@csail.mit.edu>' 53__version__ = '1.1.1' 54__revision__ = int('$Revision: 6125 $'.split()[1]) 55 56 57import ctypes 58import os 59import re 60import socket 61import sys 62 63 64 65################################################################################ 66# 67# Global setup 68# 69################################################################################ 70 71 72 73class _DummyLock(object): 74 75 @staticmethod 76 def acquire(): 77 pass 78 79 @staticmethod 80 def release(): 81 pass 82 83_global_lock = _DummyLock() 84 85 86if sys.platform == 'win32': 87 # Need to use the stdcall variants 88 _libdnssd = ctypes.windll.dnssd 89 _CFunc = ctypes.WINFUNCTYPE 90else: 91 if sys.platform == 'darwin': 92 _libdnssd = 'libSystem.B.dylib' 93 else: 94 _libdnssd = 'libdns_sd.so.1' 95 96 # If libdns_sd is actually Avahi's Bonjour compatibility 97 # layer, silence its annoying warning messages, and use a real 98 # RLock as the global lock, since the compatibility layer 99 # isn't thread safe. 100 try: 101 ctypes.cdll.LoadLibrary('libavahi-client.so.3') 102 except OSError: 103 pass 104 else: 105 os.environ['AVAHI_COMPAT_NOWARN'] = '1' 106 import threading 107 _global_lock = threading.RLock() 108 109 _libdnssd = ctypes.cdll.LoadLibrary(_libdnssd) 110 _CFunc = ctypes.CFUNCTYPE 111 112 113 114################################################################################ 115# 116# Constants 117# 118################################################################################ 119 120 121 122# 123# General flags 124# 125 126kDNSServiceFlagsMoreComing = 0x1 127kDNSServiceFlagsAdd = 0x2 128kDNSServiceFlagsDefault = 0x4 129kDNSServiceFlagsNoAutoRename = 0x8 130kDNSServiceFlagsShared = 0x10 131kDNSServiceFlagsUnique = 0x20 132kDNSServiceFlagsBrowseDomains = 0x40 133kDNSServiceFlagsRegistrationDomains = 0x80 134kDNSServiceFlagsLongLivedQuery = 0x100 135kDNSServiceFlagsAllowRemoteQuery = 0x200 136kDNSServiceFlagsForceMulticast = 0x400 137kDNSServiceFlagsReturnCNAME = 0x800 138 139 140# 141# Service classes 142# 143 144kDNSServiceClass_IN = 1 145 146 147# 148# Service types 149# 150 151kDNSServiceType_A = 1 152kDNSServiceType_NS = 2 153kDNSServiceType_MD = 3 154kDNSServiceType_MF = 4 155kDNSServiceType_CNAME = 5 156kDNSServiceType_SOA = 6 157kDNSServiceType_MB = 7 158kDNSServiceType_MG = 8 159kDNSServiceType_MR = 9 160kDNSServiceType_NULL = 10 161kDNSServiceType_WKS = 11 162kDNSServiceType_PTR = 12 163kDNSServiceType_HINFO = 13 164kDNSServiceType_MINFO = 14 165kDNSServiceType_MX = 15 166kDNSServiceType_TXT = 16 167kDNSServiceType_RP = 17 168kDNSServiceType_AFSDB = 18 169kDNSServiceType_X25 = 19 170kDNSServiceType_ISDN = 20 171kDNSServiceType_RT = 21 172kDNSServiceType_NSAP = 22 173kDNSServiceType_NSAP_PTR = 23 174kDNSServiceType_SIG = 24 175kDNSServiceType_KEY = 25 176kDNSServiceType_PX = 26 177kDNSServiceType_GPOS = 27 178kDNSServiceType_AAAA = 28 179kDNSServiceType_LOC = 29 180kDNSServiceType_NXT = 30 181kDNSServiceType_EID = 31 182kDNSServiceType_NIMLOC = 32 183kDNSServiceType_SRV = 33 184kDNSServiceType_ATMA = 34 185kDNSServiceType_NAPTR = 35 186kDNSServiceType_KX = 36 187kDNSServiceType_CERT = 37 188kDNSServiceType_A6 = 38 189kDNSServiceType_DNAME = 39 190kDNSServiceType_SINK = 40 191kDNSServiceType_OPT = 41 192kDNSServiceType_TKEY = 249 193kDNSServiceType_TSIG = 250 194kDNSServiceType_IXFR = 251 195kDNSServiceType_AXFR = 252 196kDNSServiceType_MAILB = 253 197kDNSServiceType_MAILA = 254 198kDNSServiceType_ANY = 255 199 200 201# 202# Error codes 203# 204 205kDNSServiceErr_NoError = 0 206kDNSServiceErr_Unknown = -65537 207kDNSServiceErr_NoSuchName = -65538 208kDNSServiceErr_NoMemory = -65539 209kDNSServiceErr_BadParam = -65540 210kDNSServiceErr_BadReference = -65541 211kDNSServiceErr_BadState = -65542 212kDNSServiceErr_BadFlags = -65543 213kDNSServiceErr_Unsupported = -65544 214kDNSServiceErr_NotInitialized = -65545 215kDNSServiceErr_AlreadyRegistered = -65547 216kDNSServiceErr_NameConflict = -65548 217kDNSServiceErr_Invalid = -65549 218kDNSServiceErr_Firewall = -65550 219kDNSServiceErr_Incompatible = -65551 220kDNSServiceErr_BadInterfaceIndex = -65552 221kDNSServiceErr_Refused = -65553 222kDNSServiceErr_NoSuchRecord = -65554 223kDNSServiceErr_NoAuth = -65555 224kDNSServiceErr_NoSuchKey = -65556 225kDNSServiceErr_NATTraversal = -65557 226kDNSServiceErr_DoubleNAT = -65558 227kDNSServiceErr_BadTime = -65559 228 229 230# 231# Other constants 232# 233 234kDNSServiceMaxServiceName = 64 235kDNSServiceMaxDomainName = 1005 236kDNSServiceInterfaceIndexAny = 0 237kDNSServiceInterfaceIndexLocalOnly = -1 238 239 240 241################################################################################ 242# 243# Error handling 244# 245################################################################################ 246 247 248 249class BonjourError(Exception): 250 251 """ 252 253 Exception representing an error returned by the DNS-SD library. 254 The errorCode attribute contains the actual integer error code 255 returned. 256 257 """ 258 259 _errmsg = { 260 kDNSServiceErr_NoSuchName: 'no such name', 261 kDNSServiceErr_NoMemory: 'no memory', 262 kDNSServiceErr_BadParam: 'bad param', 263 kDNSServiceErr_BadReference: 'bad reference', 264 kDNSServiceErr_BadState: 'bad state', 265 kDNSServiceErr_BadFlags: 'bad flags', 266 kDNSServiceErr_Unsupported: 'unsupported', 267 kDNSServiceErr_NotInitialized: 'not initialized', 268 kDNSServiceErr_AlreadyRegistered: 'already registered', 269 kDNSServiceErr_NameConflict: 'name conflict', 270 kDNSServiceErr_Invalid: 'invalid', 271 kDNSServiceErr_Firewall: 'firewall', 272 kDNSServiceErr_Incompatible: 'incompatible', 273 kDNSServiceErr_BadInterfaceIndex: 'bad interface index', 274 kDNSServiceErr_Refused: 'refused', 275 kDNSServiceErr_NoSuchRecord: 'no such record', 276 kDNSServiceErr_NoAuth: 'no auth', 277 kDNSServiceErr_NoSuchKey: 'no such key', 278 kDNSServiceErr_NATTraversal: 'NAT traversal', 279 kDNSServiceErr_DoubleNAT: 'double NAT', 280 kDNSServiceErr_BadTime: 'bad time', 281 } 282 283 @classmethod 284 def _errcheck(cls, result, func, args): 285 if result != kDNSServiceErr_NoError: 286 raise cls(result) 287 return args 288 289 def __init__(self, errorCode): 290 self.errorCode = errorCode 291 Exception.__init__(self, 292 (errorCode, self._errmsg.get(errorCode, 'unknown'))) 293 294 295 296################################################################################ 297# 298# Data types 299# 300################################################################################ 301 302 303 304class _utf8_char_p(ctypes.c_char_p): 305 306 @classmethod 307 def from_param(cls, obj): 308 if (obj is not None) and (not isinstance(obj, cls)): 309 if not str(obj): 310 raise TypeError('parameter must be a string type instance') 311 312 obj = obj.encode('utf-8') 313 return ctypes.c_char_p.from_param(obj) 314 315 def decode(self): 316 if self.value is None: 317 return None 318 return self.value.decode('utf-8') 319 320 321class _utf8_char_p_non_null(_utf8_char_p): 322 323 @classmethod 324 def from_param(cls, obj): 325 if obj is None: 326 raise ValueError('parameter cannot be None') 327 return _utf8_char_p.from_param(obj) 328 329 330_DNSServiceFlags = ctypes.c_uint32 331_DNSServiceErrorType = ctypes.c_int32 332 333 334class DNSRecordRef(ctypes.c_void_p): 335 336 """ 337 338 A DNSRecordRef pointer. DO NOT CREATE INSTANCES OF THIS CLASS! 339 Only instances returned by the DNS-SD library are valid. Using 340 others will likely cause the Python interpreter to crash. 341 342 Application code should not use any of the methods of this class. 343 The only valid use of a DNSRecordRef instance is as an argument to 344 a DNS-SD function. 345 346 To compare two DNSRecordRef instances for equality, use '==' 347 rather than 'is'. 348 349 """ 350 351 @classmethod 352 def from_param(cls, obj): 353 if type(obj) is not cls: 354 raise TypeError("expected '%s', got '%s'" % 355 (cls.__name__, type(obj).__name__)) 356 if obj.value is None: 357 raise ValueError('invalid %s instance' % cls.__name__) 358 return obj 359 360 def __eq__(self, other): 361 return ((type(other) is type(self)) and (other.value == self.value)) 362 363 def __ne__(self, other): 364 return not (other == self) 365 366 def _invalidate(self): 367 self.value = None 368 369 def _valid(self): 370 return (self.value is not None) 371 372 373class _DNSRecordRef_or_null(DNSRecordRef): 374 375 @classmethod 376 def from_param(cls, obj): 377 if obj is None: 378 return obj 379 return DNSRecordRef.from_param(obj) 380 381 382class DNSServiceRef(DNSRecordRef): 383 384 """ 385 386 A DNSServiceRef pointer. DO NOT CREATE INSTANCES OF THIS CLASS! 387 Only instances returned by the DNS-SD library are valid. Using 388 others will likely cause the Python interpreter to crash. 389 390 An instance of this class represents an active connection to the 391 mDNS daemon. The connection remains open until the close() method 392 is called (which also terminates the associated browse, resolve, 393 etc.). Note that this method is *not* called automatically when 394 the instance is deallocated; therefore, application code must be 395 certain to call close() when the connection is no longer needed. 396 397 The primary use of a DNSServiceRef instance is in conjunction with 398 select() or poll() to determine when a response from the daemon is 399 available. When the file descriptor returned by fileno() is ready 400 for reading, a reply from the daemon is available and should be 401 processed by passing the DNSServiceRef instance to 402 DNSServiceProcessResult(), which will invoke the appropriate 403 application callback function. (Note that the file descriptor 404 should never be read from or written to directly.) 405 406 The DNSServiceRef class supports the context management protocol 407 introduced in Python 2.5, meaning applications can use the 'with' 408 statement to ensure that DNSServiceRef instances are closed 409 regardless of whether an exception occurs, e.g. 410 411 sdRef = DNSServiceBrowse(...) 412 with sdRef: 413 # sdRef will be closed regardless of how this block is 414 # exited 415 ... 416 417 To compare two DNSServiceRef instances for equality, use '==' 418 rather than 'is'. 419 420 """ 421 422 def __init__(self, *args, **kwargs): 423 DNSRecordRef.__init__(self, *args, **kwargs) 424 425 # Since callback functions are called asynchronously, we need 426 # to hold onto references to them for as long as they're in 427 # use. Otherwise, Python could deallocate them before we call 428 # DNSServiceProcessResult(), meaning the Bonjour library would 429 # dereference freed memory when it tried to invoke the 430 # callback. 431 self._callbacks = [] 432 433 # A DNSRecordRef is invalidated if DNSServiceRefDeallocate() 434 # is called on the corresponding DNSServiceRef, so we need to 435 # keep track of all our record refs and invalidate them when 436 # we're closed. 437 self._record_refs = [] 438 439 def __enter__(self): 440 return self 441 442 def __exit__(self, type, value, traceback): 443 self.close() 444 445 def _add_callback(self, cb): 446 self._callbacks.append(cb) 447 448 def _add_record_ref(self, ref): 449 self._record_refs.append(ref) 450 451 def close(self): 452 """ 453 454 Close the connection to the mDNS daemon and terminate any 455 associated browse, resolve, etc. operations. 456 457 """ 458 459 if self._valid(): 460 for ref in self._record_refs: 461 ref._invalidate() 462 del self._record_refs 463 464 _global_lock.acquire() 465 try: 466 _DNSServiceRefDeallocate(self) 467 finally: 468 _global_lock.release() 469 470 self._invalidate() 471 del self._callbacks 472 473 def fileno(self): 474 """ 475 476 Return the file descriptor associated with this connection. 477 This descriptor should never be read from or written to 478 directly. It should only be passed to select() or poll() to 479 determine when a response from the mDNS daemon is available. 480 481 """ 482 483 _global_lock.acquire() 484 try: 485 fd = _DNSServiceRefSockFD(self) 486 finally: 487 _global_lock.release() 488 489 return fd 490 491 492_DNSServiceDomainEnumReply = _CFunc( 493 None, 494 DNSServiceRef, # sdRef 495 _DNSServiceFlags, # flags 496 ctypes.c_uint32, # interfaceIndex 497 _DNSServiceErrorType, # errorCode 498 _utf8_char_p, # replyDomain 499 ctypes.c_void_p, # context 500 ) 501 502 503_DNSServiceRegisterReply = _CFunc( 504 None, 505 DNSServiceRef, # sdRef 506 _DNSServiceFlags, # flags 507 _DNSServiceErrorType, # errorCode 508 _utf8_char_p, # name 509 _utf8_char_p, # regtype 510 _utf8_char_p, # domain 511 ctypes.c_void_p, # context 512 ) 513 514 515_DNSServiceBrowseReply = _CFunc( 516 None, 517 DNSServiceRef, # sdRef 518 _DNSServiceFlags, # flags 519 ctypes.c_uint32, # interfaceIndex 520 _DNSServiceErrorType, # errorCode 521 _utf8_char_p, # serviceName 522 _utf8_char_p, # regtype 523 _utf8_char_p, # replyDomain 524 ctypes.c_void_p, # context 525 ) 526 527 528_DNSServiceResolveReply = _CFunc( 529 None, 530 DNSServiceRef, # sdRef 531 _DNSServiceFlags, # flags 532 ctypes.c_uint32, # interfaceIndex 533 _DNSServiceErrorType, # errorCode 534 _utf8_char_p, # fullname 535 _utf8_char_p, # hosttarget 536 ctypes.c_uint16, # port 537 ctypes.c_uint16, # txtLen 538 ctypes.c_void_p, # txtRecord (not null-terminated, so c_void_p) 539 ctypes.c_void_p, # context 540 ) 541 542 543_DNSServiceRegisterRecordReply = _CFunc( 544 None, 545 DNSServiceRef, # sdRef 546 DNSRecordRef, # RecordRef 547 _DNSServiceFlags, # flags 548 _DNSServiceErrorType, # errorCode 549 ctypes.c_void_p, # context 550 ) 551 552 553_DNSServiceQueryRecordReply = _CFunc( 554 None, 555 DNSServiceRef, # sdRef 556 _DNSServiceFlags, # flags 557 ctypes.c_uint32, # interfaceIndex 558 _DNSServiceErrorType, # errorCode 559 _utf8_char_p, # fullname 560 ctypes.c_uint16, # rrtype 561 ctypes.c_uint16, # rrclass 562 ctypes.c_uint16, # rdlen 563 ctypes.c_void_p, # rdata 564 ctypes.c_uint32, # ttl 565 ctypes.c_void_p, # context 566 ) 567 568 569 570################################################################################ 571# 572# Low-level function bindings 573# 574################################################################################ 575 576 577 578def _create_function_bindings(): 579 580 ERRCHECK = True 581 NO_ERRCHECK = False 582 583 OUTPARAM = (lambda index: index) 584 NO_OUTPARAM = None 585 586 specs = { 587 588 #'funcname': 589 #( 590 # return_type, 591 # errcheck, 592 # outparam, 593 # ( 594 # param_1_type, 595 # param_2_type, 596 # ... 597 # param_n_type, 598 # )), 599 600 'DNSServiceRefSockFD': 601 ( 602 ctypes.c_int, 603 NO_ERRCHECK, 604 NO_OUTPARAM, 605 ( 606 DNSServiceRef, # sdRef 607 )), 608 609 'DNSServiceProcessResult': 610 ( 611 _DNSServiceErrorType, 612 ERRCHECK, 613 NO_OUTPARAM, 614 ( 615 DNSServiceRef, # sdRef 616 )), 617 618 'DNSServiceRefDeallocate': 619 ( 620 None, 621 NO_ERRCHECK, 622 NO_OUTPARAM, 623 ( 624 DNSServiceRef, # sdRef 625 )), 626 627 'DNSServiceEnumerateDomains': 628 ( 629 _DNSServiceErrorType, 630 ERRCHECK, 631 OUTPARAM(0), 632 ( 633 ctypes.POINTER(DNSServiceRef), # sdRef 634 _DNSServiceFlags, # flags 635 ctypes.c_uint32, # interfaceIndex 636 _DNSServiceDomainEnumReply, # callBack 637 ctypes.c_void_p, # context 638 )), 639 640 'DNSServiceRegister': 641 ( 642 _DNSServiceErrorType, 643 ERRCHECK, 644 OUTPARAM(0), 645 ( 646 ctypes.POINTER(DNSServiceRef), # sdRef 647 _DNSServiceFlags, # flags 648 ctypes.c_uint32, # interfaceIndex 649 _utf8_char_p, # name 650 _utf8_char_p_non_null, # regtype 651 _utf8_char_p, # domain 652 _utf8_char_p, # host 653 ctypes.c_uint16, # port 654 ctypes.c_uint16, # txtLen 655 ctypes.c_void_p, # txtRecord 656 _DNSServiceRegisterReply, # callBack 657 ctypes.c_void_p, # context 658 )), 659 660 'DNSServiceAddRecord': 661 ( 662 _DNSServiceErrorType, 663 ERRCHECK, 664 OUTPARAM(1), 665 ( 666 DNSServiceRef, # sdRef 667 ctypes.POINTER(DNSRecordRef), # RecordRef 668 _DNSServiceFlags, # flags 669 ctypes.c_uint16, # rrtype 670 ctypes.c_uint16, # rdlen 671 ctypes.c_void_p, # rdata 672 ctypes.c_uint32, # ttl 673 )), 674 675 'DNSServiceUpdateRecord': 676 ( 677 _DNSServiceErrorType, 678 ERRCHECK, 679 NO_OUTPARAM, 680 ( 681 DNSServiceRef, # sdRef 682 _DNSRecordRef_or_null, # RecordRef 683 _DNSServiceFlags, # flags 684 ctypes.c_uint16, # rdlen 685 ctypes.c_void_p, # rdata 686 ctypes.c_uint32, # ttl 687 )), 688 689 'DNSServiceRemoveRecord': 690 ( 691 _DNSServiceErrorType, 692 ERRCHECK, 693 NO_OUTPARAM, 694 ( 695 DNSServiceRef, # sdRef 696 DNSRecordRef, # RecordRef 697 _DNSServiceFlags, # flags 698 )), 699 700 'DNSServiceBrowse': 701 ( 702 _DNSServiceErrorType, 703 ERRCHECK, 704 OUTPARAM(0), 705 ( 706 ctypes.POINTER(DNSServiceRef), # sdRef 707 _DNSServiceFlags, # flags 708 ctypes.c_uint32, # interfaceIndex 709 _utf8_char_p_non_null, # regtype 710 _utf8_char_p, # domain 711 _DNSServiceBrowseReply, # callBack 712 ctypes.c_void_p, # context 713 )), 714 715 'DNSServiceResolve': 716 ( 717 _DNSServiceErrorType, 718 ERRCHECK, 719 OUTPARAM(0), 720 ( 721 ctypes.POINTER(DNSServiceRef), # sdRef 722 _DNSServiceFlags, # flags 723 ctypes.c_uint32, # interfaceIndex 724 _utf8_char_p_non_null, # name 725 _utf8_char_p_non_null, # regtype 726 _utf8_char_p_non_null, # domain 727 _DNSServiceResolveReply, # callBack 728 ctypes.c_void_p, # context 729 )), 730 731 'DNSServiceCreateConnection': 732 ( 733 _DNSServiceErrorType, 734 ERRCHECK, 735 OUTPARAM(0), 736 ( 737 ctypes.POINTER(DNSServiceRef), # sdRef 738 )), 739 740 'DNSServiceRegisterRecord': 741 ( 742 _DNSServiceErrorType, 743 ERRCHECK, 744 OUTPARAM(1), 745 ( 746 DNSServiceRef, # sdRef 747 ctypes.POINTER(DNSRecordRef), # RecordRef 748 _DNSServiceFlags, # flags 749 ctypes.c_uint32, # interfaceIndex 750 _utf8_char_p_non_null, # fullname 751 ctypes.c_uint16, # rrtype 752 ctypes.c_uint16, # rrclass 753 ctypes.c_uint16, # rdlen 754 ctypes.c_void_p, # rdata 755 ctypes.c_uint32, # ttl 756 _DNSServiceRegisterRecordReply, # callBack 757 ctypes.c_void_p, # context 758 )), 759 760 'DNSServiceQueryRecord': 761 ( 762 _DNSServiceErrorType, 763 ERRCHECK, 764 OUTPARAM(0), 765 ( 766 ctypes.POINTER(DNSServiceRef), # sdRef 767 _DNSServiceFlags, # flags 768 ctypes.c_uint32, # interfaceIndex 769 _utf8_char_p_non_null, # fullname 770 ctypes.c_uint16, # rrtype 771 ctypes.c_uint16, # rrclass 772 _DNSServiceQueryRecordReply, # callBack 773 ctypes.c_void_p, # context 774 )), 775 776 'DNSServiceReconfirmRecord': 777 ( 778 None, # _DNSServiceErrorType in more recent versions 779 NO_ERRCHECK, 780 NO_OUTPARAM, 781 ( 782 _DNSServiceFlags, # flags 783 ctypes.c_uint32, # interfaceIndex 784 _utf8_char_p_non_null, # fullname 785 ctypes.c_uint16, # rrtype 786 ctypes.c_uint16, # rrclass 787 ctypes.c_uint16, # rdlen 788 ctypes.c_void_p, # rdata 789 )), 790 791 'DNSServiceConstructFullName': 792 ( 793 ctypes.c_int, 794 ERRCHECK, 795 OUTPARAM(0), 796 ( 797 ctypes.c_char * kDNSServiceMaxDomainName, # fullName 798 _utf8_char_p, # service 799 _utf8_char_p_non_null, # regtype 800 _utf8_char_p_non_null, # domain 801 )), 802 803 } 804 805 806 for name, (restype, errcheck, outparam, argtypes) in specs.items(): 807 prototype = _CFunc(restype, *argtypes) 808 809 paramflags = [1] * len(argtypes) 810 if outparam is not None: 811 paramflags[outparam] = 2 812 paramflags = tuple((val,) for val in paramflags) 813 814 func = prototype((name, _libdnssd), paramflags) 815 816 if errcheck: 817 func.errcheck = BonjourError._errcheck 818 819 globals()['_' + name] = func 820 821 822# Only need to do this once 823_create_function_bindings() 824del _create_function_bindings 825 826 827 828################################################################################ 829# 830# Internal utility types and functions 831# 832################################################################################ 833 834 835 836class _NoDefault(object): 837 838 def __repr__(self): 839 return '<NO DEFAULT>' 840 841 def check(self, obj): 842 if obj is self: 843 raise ValueError('required parameter value missing') 844 845_NO_DEFAULT = _NoDefault() 846 847 848def _string_to_length_and_void_p(string): 849 if isinstance(string, TXTRecord): 850 string = str(string) 851 void_p = ctypes.cast(ctypes.c_char_p(string), ctypes.c_void_p) 852 return len(string), void_p 853 854 855def _length_and_void_p_to_string(length, void_p): 856 char_p = ctypes.cast(void_p, ctypes.POINTER(ctypes.c_char)) 857 return ''.join(char_p[i].decode('utf-8') for i in range(length)) 858 859 860 861################################################################################ 862# 863# High-level functions 864# 865################################################################################ 866 867 868 869def DNSServiceProcessResult( 870 sdRef, 871 ): 872 873 """ 874 875 Read a reply from the daemon, calling the appropriate application 876 callback. This call will block until the daemon's response is 877 received. Use sdRef in conjunction with select() or poll() to 878 determine the presence of a response from the server before 879 calling this function to process the reply without blocking. Call 880 this function at any point if it is acceptable to block until the 881 daemon's response arrives. Note that the client is responsible 882 for ensuring that DNSServiceProcessResult() is called whenever 883 there is a reply from the daemon; the daemon may terminate its 884 connection with a client that does not process the daemon's 885 responses. 886 887 sdRef: 888 A DNSServiceRef returned by any of the DNSService calls that 889 take a callback parameter. 890 891 """ 892 893 _global_lock.acquire() 894 try: 895 _DNSServiceProcessResult(sdRef) 896 finally: 897 _global_lock.release() 898 899 900def DNSServiceEnumerateDomains( 901 flags, 902 interfaceIndex = kDNSServiceInterfaceIndexAny, 903 callBack = None, 904 ): 905 906 """ 907 908 Asynchronously enumerate domains available for browsing and 909 registration. 910 911 The enumeration MUST be cancelled by closing the returned 912 DNSServiceRef when no more domains are to be found. 913 914 flags: 915 Possible values are: 916 kDNSServiceFlagsBrowseDomains to enumerate domains 917 recommended for browsing. 918 kDNSServiceFlagsRegistrationDomains to enumerate domains 919 recommended for registration. 920 921 interfaceIndex: 922 If non-zero, specifies the interface on which to look for 923 domains. Most applications will pass 924 kDNSServiceInterfaceIndexAny (0) to enumerate domains on all 925 interfaces. 926 927 callBack: 928 The function to be called when a domain is found or the call 929 asynchronously fails. Its signature should be 930 callBack(sdRef, flags, interfaceIndex, errorCode, replyDomain). 931 932 return value: 933 A DNSServiceRef instance. 934 935 Callback Parameters: 936 937 sdRef: 938 The DNSServiceRef returned by DNSServiceEnumerateDomains(). 939 940 flags: 941 Possible values are: 942 kDNSServiceFlagsMoreComing 943 kDNSServiceFlagsAdd 944 kDNSServiceFlagsDefault 945 946 interfaceIndex: 947 Specifies the interface on which the domain exists. 948 949 errorCode: 950 Will be kDNSServiceErr_NoError (0) on success, otherwise 951 indicates the failure that occurred (in which case other 952 parameters are undefined). 953 954 replyDomain: 955 The name of the domain. 956 957 """ 958 959 @_DNSServiceDomainEnumReply 960 def _callback(sdRef, flags, interfaceIndex, errorCode, replyDomain, 961 context): 962 if callBack is not None: 963 callBack(sdRef, flags, interfaceIndex, errorCode, 964 replyDomain.decode()) 965 966 _global_lock.acquire() 967 try: 968 sdRef = _DNSServiceEnumerateDomains(flags, 969 interfaceIndex, 970 _callback, 971 None) 972 finally: 973 _global_lock.release() 974 975 sdRef._add_callback(_callback) 976 977 return sdRef 978 979 980def DNSServiceRegister( 981 flags = 0, 982 interfaceIndex = kDNSServiceInterfaceIndexAny, 983 name = None, 984 regtype = _NO_DEFAULT, 985 domain = None, 986 host = None, 987 port = _NO_DEFAULT, 988 txtRecord = '', 989 callBack = None, 990 ): 991 992 """ 993 994 Register a service that is discovered via DNSServiceBrowse() and 995 DNSServiceResolve() calls. 996 997 flags: 998 Indicates the renaming behavior on name conflict. Most 999 applications will pass 0. 1000 1001 interfaceIndex: 1002 If non-zero, specifies the interface on which to register the 1003 service. Most applications will pass 1004 kDNSServiceInterfaceIndexAny (0) to register on all available 1005 interfaces. 1006 1007 name: 1008 If not None, specifies the service name to be registered. 1009 Most applications will not specify a name, in which case the 1010 computer name is used. (This name is communicated to the 1011 client via the callback.) If a name is specified, it must be 1012 1-63 bytes of UTF-8 text. If the name is longer than 63 1013 bytes, it will be automatically truncated to a legal length, 1014 unless the flag kDNSServiceFlagsNoAutoRename is set, in which 1015 case a BonjourError exception will be thrown. 1016 1017 regtype: 1018 The service type followed by the protocol, separated by a dot 1019 (e.g. "_ftp._tcp"). The service type must be an underscore, 1020 followed by 1-14 characters, which may be letters, digits, or 1021 hyphens. The transport protocol must be "_tcp" or "_udp". New 1022 service types should be registered at 1023 <http://www.dns-sd.org/ServiceTypes.html>. 1024 1025 domain: 1026 If not None, specifies the domain on which to advertise the 1027 service. Most applications will not specify a domain, instead 1028 automatically registering in the default domain(s). 1029 1030 host: 1031 If not None, specifies the SRV target host name. Most 1032 applications will not specify a host, instead automatically 1033 using the machine's default host name(s). Note that 1034 specifying a host name does NOT create an address record for 1035 that host; the application is responsible for ensuring that 1036 the appropriate address record exists, or creating it via 1037 DNSServiceRegisterRecord(). 1038 1039 port: 1040 The port, in host (not network) byte order, on which the 1041 service accepts connections. Pass 0 for a "placeholder" 1042 service (i.e. a service that will not be discovered by 1043 browsing, but will cause a name conflict if another client 1044 tries to register that same name). Most clients will not use 1045 placeholder services. 1046 1047 txtRecord: 1048 The TXT record rdata. If not None, txtRecord must be either a 1049 TXTRecord instance or a string containing a properly formatted 1050 DNS TXT record, i.e. 1051 <length byte> <data> <length byte> <data> ... 1052 1053 callBack: 1054 The function to be called when the registration completes or 1055 asynchronously fails. Its signature should be 1056 callBack(sdRef, flags, errorCode, name, regtype, domain). 1057 The client MAY pass None for the callback, in which case the 1058 client will NOT be notified of the default values picked on 1059 its behalf, and the client will NOT be notified of any 1060 asynchronous errors (e.g. out of memory errors, etc.) that may 1061 prevent the registration of the service. The client may NOT 1062 pass the flag kDNSServiceFlagsNoAutoRename if the callback is 1063 None. The client may still deregister the service at any time 1064 by closing the returned DNSServiceRef. 1065 1066 return value: 1067 A DNSServiceRef instance. The registration will remain active 1068 indefinitely until the client terminates it by closing the 1069 DNSServiceRef. 1070 1071 Callback Parameters: 1072 1073 sdRef: 1074 The DNSServiceRef returned by DNSServiceRegister(). 1075 1076 flags: 1077 Currently unused, reserved for future use. 1078 1079 errorCode: 1080 Will be kDNSServiceErr_NoError on success, otherwise will 1081 indicate the failure that occurred (including name conflicts, 1082 if the kDNSServiceFlagsNoAutoRename flag was used when 1083 registering). Other parameters are undefined if an error 1084 occurred. 1085 1086 name: 1087 The service name registered. (If the application did not 1088 specify a name in DNSServiceRegister(), this indicates what 1089 name was automatically chosen.) 1090 1091 regtype: 1092 The type of service registered, as it was passed to the 1093 callout. 1094 1095 domain: 1096 The domain on which the service was registered. (If the 1097 application did not specify a domain in DNSServiceRegister(), 1098 this indicates the default domain on which the service was 1099 registered.) 1100 1101 """ 1102 1103 _NO_DEFAULT.check(regtype) 1104 _NO_DEFAULT.check(port) 1105 1106 port = socket.htons(port) 1107 1108 # From here on txtRecord has to be a bytes type, so convert what 1109 # we have: 1110 if type(txtRecord) == TXTRecord: 1111 txtRecord = str(txtRecord).encode('utf-8') 1112 elif type(txtRecord) == str: 1113 txtRecord = txtRecord.encode('utf-8') 1114 else: 1115 raise TypeError('txtRecord is unhandlable type: {type}'.format( 1116 type=type(txtRecord))) 1117 1118 if not txtRecord: 1119 txtLen, txtRecord = 1, '\0'.encode('utf-8') 1120 else: 1121 txtLen, txtRecord = _string_to_length_and_void_p(txtRecord) 1122 1123 @_DNSServiceRegisterReply 1124 def _callback(sdRef, flags, errorCode, name, regtype, domain, context): 1125 if callBack is not None: 1126 callBack(sdRef, flags, errorCode, name.decode(), regtype.decode(), 1127 domain.decode()) 1128 1129 _global_lock.acquire() 1130 try: 1131 sdRef = _DNSServiceRegister(flags, 1132 interfaceIndex, 1133 name, 1134 regtype, 1135 domain, 1136 host, 1137 port, 1138 txtLen, 1139 txtRecord, 1140 _callback, 1141 None) 1142 finally: 1143 _global_lock.release() 1144 1145 sdRef._add_callback(_callback) 1146 1147 return sdRef 1148 1149 1150def DNSServiceAddRecord( 1151 sdRef, 1152 flags = 0, 1153 rrtype = _NO_DEFAULT, 1154 rdata = _NO_DEFAULT, 1155 ttl = 0, 1156 ): 1157 1158 """ 1159 1160 Add a record to a registered service. The name of the record will 1161 be the same as the registered service's name. The record can 1162 later be updated or deregistered by passing the DNSRecordRef 1163 returned by this function to DNSServiceUpdateRecord() or 1164 DNSServiceRemoveRecord(). 1165 1166 Note that DNSServiceAddRecord/UpdateRecord/RemoveRecord are NOT 1167 thread-safe with respect to a single DNSServiceRef. If you plan 1168 to have multiple threads in your program simultaneously add, 1169 update, or remove records from the same DNSServiceRef, then it's 1170 the caller's responsibility to use a lock or take similar 1171 appropriate precautions to serialize those calls. 1172 1173 sdRef: 1174 A DNSServiceRef returned by DNSServiceRegister(). 1175 1176 flags: 1177 Currently ignored, reserved for future use. 1178 1179 rrtype: 1180 The type of the record (e.g. kDNSServiceType_TXT, 1181 kDNSServiceType_SRV, etc.). 1182 1183 rdata: 1184 A string containing the raw rdata to be contained in the added 1185 resource record. 1186 1187 ttl: 1188 The time to live of the resource record, in seconds. Pass 0 1189 to use a default value. 1190 1191 return value: 1192 A DNSRecordRef instance, which may be passed to 1193 DNSServiceUpdateRecord() or DNSServiceRemoveRecord(). If 1194 sdRef is closed, the DNSRecordRef is also invalidated and may 1195 not be used further. 1196 1197 """ 1198 1199 _NO_DEFAULT.check(rrtype) 1200 _NO_DEFAULT.check(rdata) 1201 1202 rdlen, rdata = _string_to_length_and_void_p(rdata) 1203 1204 _global_lock.acquire() 1205 try: 1206 RecordRef = _DNSServiceAddRecord(sdRef, 1207 flags, 1208 rrtype, 1209 rdlen, 1210 rdata, 1211 ttl) 1212 finally: 1213 _global_lock.release() 1214 1215 sdRef._add_record_ref(RecordRef) 1216 1217 return RecordRef 1218 1219 1220def DNSServiceUpdateRecord( 1221 sdRef, 1222 RecordRef = None, 1223 flags = 0, 1224 rdata = _NO_DEFAULT, 1225 ttl = 0, 1226 ): 1227 1228 """ 1229 1230 Update a registered resource record. The record must either be: 1231 - The primary txt record of a service registered via 1232 DNSServiceRegister(), or 1233 - A record added to a registered service via 1234 DNSServiceAddRecord(), or 1235 - An individual record registered by DNSServiceRegisterRecord() 1236 1237 sdRef: 1238 A DNSServiceRef returned by DNSServiceRegister() or 1239 DNSServiceCreateConnection(). 1240 1241 RecordRef: 1242 A DNSRecordRef returned by DNSServiceAddRecord(), or None to 1243 update the service's primary txt record. 1244 1245 flags: 1246 Currently ignored, reserved for future use. 1247 1248 rdata: 1249 A string containing the new rdata to be contained in the 1250 updated resource record. 1251 1252 ttl: 1253 The time to live of the updated resource record, in seconds. 1254 1255 """ 1256 1257 _NO_DEFAULT.check(rdata) 1258 1259 rdlen, rdata = _string_to_length_and_void_p(rdata) 1260 1261 _global_lock.acquire() 1262 try: 1263 _DNSServiceUpdateRecord(sdRef, 1264 RecordRef, 1265 flags, 1266 rdlen, 1267 rdata, 1268 ttl) 1269 finally: 1270 _global_lock.release() 1271 1272 1273def DNSServiceRemoveRecord( 1274 sdRef, 1275 RecordRef, 1276 flags = 0, 1277 ): 1278 1279 """ 1280 1281 Remove a record previously added to a service record set via 1282 DNSServiceAddRecord(), or deregister a record registered 1283 individually via DNSServiceRegisterRecord(). 1284 1285 sdRef: 1286 A DNSServiceRef returned by DNSServiceRegister() (if the 1287 record being removed was registered via DNSServiceAddRecord()) 1288 or by DNSServiceCreateConnection() (if the record being 1289 removed was registered via DNSServiceRegisterRecord()). 1290 1291 recordRef: 1292 A DNSRecordRef returned by DNSServiceAddRecord() or 1293 DNSServiceRegisterRecord(). 1294 1295 flags: 1296 Currently ignored, reserved for future use. 1297 1298 """ 1299 1300 _global_lock.acquire() 1301 try: 1302 _DNSServiceRemoveRecord(sdRef, 1303 RecordRef, 1304 flags) 1305 finally: 1306 _global_lock.release() 1307 1308 RecordRef._invalidate() 1309 1310 1311def DNSServiceBrowse( 1312 flags = 0, 1313 interfaceIndex = kDNSServiceInterfaceIndexAny, 1314 regtype = _NO_DEFAULT, 1315 domain = None, 1316 callBack = None, 1317 ): 1318 1319 """ 1320 1321 Browse for instances of a service. 1322 1323 flags: 1324 Currently ignored, reserved for future use. 1325 1326 interfaceIndex: 1327 If non-zero, specifies the interface on which to browse for 1328 services. Most applications will pass 1329 kDNSServiceInterfaceIndexAny (0) to browse on all available 1330 interfaces. 1331 1332 regtype: 1333 The service type being browsed for followed by the protocol, 1334 separated by a dot (e.g. "_ftp._tcp"). The transport protocol 1335 must be "_tcp" or "_udp". 1336 1337 domain: 1338 If not None, specifies the domain on which to browse for 1339 services. Most applications will not specify a domain, 1340 instead browsing on the default domain(s). 1341 1342 callBack: 1343 The function to be called when an instance of the service 1344 being browsed for is found, or if the call asynchronously 1345 fails. Its signature should be 1346 callBack(sdRef, flags, interfaceIndex, errorCode, 1347 serviceName, regtype, replyDomain). 1348 1349 return value: 1350 A DNSServiceRef instance. The browse operation will run 1351 indefinitely until the client terminates it by closing the 1352 DNSServiceRef. 1353 1354 Callback Parameters: 1355 1356 sdRef: 1357 The DNSServiceRef returned by DNSServiceBrowse(). 1358 1359 flags: 1360 Possible values are kDNSServiceFlagsMoreComing and 1361 kDNSServiceFlagsAdd. 1362 1363 interfaceIndex: 1364 The interface on which the service is advertised. This index 1365 should be passed to DNSServiceResolve() when resolving the 1366 service. 1367 1368 errorCode: 1369 Will be kDNSServiceErr_NoError (0) on success, otherwise will 1370 indicate the failure that occurred. Other parameters are 1371 undefined if an error occurred. 1372 1373 serviceName: 1374 The discovered service name. This name should be displayed to 1375 the user and stored for subsequent use in the 1376 DNSServiceResolve() call. 1377 1378 regtype: 1379 The service type, which is usually (but not always) the same 1380 as was passed to DNSServiceBrowse(). One case where the 1381 discovered service type may not be the same as the requested 1382 service type is when using subtypes: The client may want to 1383 browse for only those ftp servers that allow anonymous 1384 connections. The client will pass the string 1385 "_ftp._tcp,_anon" to DNSServiceBrowse(), but the type of the 1386 service that's discovered is simply "_ftp._tcp". The regtype 1387 for each discovered service instance should be stored along 1388 with the name, so that it can be passed to DNSServiceResolve() 1389 when the service is later resolved. 1390 1391 replyDomain: 1392 The domain of the discovered service instance. This may or 1393 may not be the same as the domain that was passed to 1394 DNSServiceBrowse(). The domain for each discovered service 1395 instance should be stored along with the name, so that it can 1396 be passed to DNSServiceResolve() when the service is later 1397 resolved. 1398 1399 """ 1400 1401 _NO_DEFAULT.check(regtype) 1402 1403 @_DNSServiceBrowseReply 1404 def _callback(sdRef, flags, interfaceIndex, errorCode, serviceName, regtype, 1405 replyDomain, context): 1406 if callBack is not None: 1407 callBack(sdRef, flags, interfaceIndex, errorCode, 1408 serviceName.decode(), regtype.decode(), 1409 replyDomain.decode()) 1410 1411 _global_lock.acquire() 1412 try: 1413 sdRef = _DNSServiceBrowse(flags, 1414 interfaceIndex, 1415 regtype, 1416 domain, 1417 _callback, 1418 None) 1419 finally: 1420 _global_lock.release() 1421 1422 sdRef._add_callback(_callback) 1423 1424 return sdRef 1425 1426 1427def DNSServiceResolve( 1428 flags = 0, 1429 interfaceIndex = _NO_DEFAULT, 1430 name = _NO_DEFAULT, 1431 regtype = _NO_DEFAULT, 1432 domain = _NO_DEFAULT, 1433 callBack = None, 1434 ): 1435 1436 """ 1437 1438 Resolve a service name discovered via DNSServiceBrowse() to a 1439 target host name, port number, and txt record. 1440 1441 Note: Applications should NOT use DNSServiceResolve() solely for 1442 txt record monitoring; use DNSServiceQueryRecord() instead, as it 1443 is more efficient for this task. 1444 1445 Note: When the desired results have been returned, the client MUST 1446 terminate the resolve by closing the returned DNSServiceRef. 1447 1448 Note: DNSServiceResolve() behaves correctly for typical services 1449 that have a single SRV record and a single TXT record. To resolve 1450 non-standard services with multiple SRV or TXT records, 1451 DNSServiceQueryRecord() should be used. 1452 1453 flags: 1454 Currently ignored, reserved for future use. 1455 1456 interfaceIndex: 1457 The interface on which to resolve the service. If this 1458 resolve call is as a result of a currently active 1459 DNSServiceBrowse() operation, then the interfaceIndex should 1460 be the index reported in the browse callback. If this resolve 1461 call is using information previously saved (e.g. in a 1462 preference file) for later use, then use 1463 kDNSServiceInterfaceIndexAny (0), because the desired service 1464 may now be reachable via a different physical interface. 1465 1466 name: 1467 The name of the service instance to be resolved, as reported 1468 to the DNSServiceBrowse() callback. 1469 1470 regtype: 1471 The type of the service instance to be resolved, as reported 1472 to the DNSServiceBrowse() callback. 1473 1474 domain: 1475 The domain of the service instance to be resolved, as reported 1476 to the DNSServiceBrowse() callback. 1477 1478 callBack: 1479 The function to be called when a result is found, or if the 1480 call asynchronously fails. Its signature should be 1481 callBack(sdRef, flags, interfaceIndex, errorCode, fullname, 1482 hosttarget, port, txtRecord). 1483 1484 return value: 1485 A DNSServiceRef instance. The resolve operation will run 1486 indefinitely until the client terminates it by closing the 1487 DNSServiceRef. 1488 1489 Callback Parameters: 1490 1491 sdRef: 1492 The DNSServiceRef returned by DNSServiceResolve(). 1493 1494 flags: 1495 Currently unused, reserved for future use. 1496 1497 interfaceIndex: 1498 The interface on which the service was resolved. 1499 1500 errorCode: 1501 Will be kDNSServiceErr_NoError (0) on success, otherwise will 1502 indicate the failure that occurred. Other parameters are 1503 undefined if an error occurred. 1504 1505 fullname: 1506 The full service domain name, in the form 1507 <servicename>.<protocol>.<domain>. 1508 1509 hosttarget: 1510 The target hostname of the machine providing the service. 1511 1512 port: 1513 The port, in host (not network) byte order, on which 1514 connections are accepted for this service. 1515 1516 txtRecord: 1517 A string containing the service's primary txt record, in 1518 standard txt record format. 1519 1520 """ 1521 1522 _NO_DEFAULT.check(interfaceIndex) 1523 _NO_DEFAULT.check(name) 1524 _NO_DEFAULT.check(regtype) 1525 _NO_DEFAULT.check(domain) 1526 1527 @_DNSServiceResolveReply 1528 def _callback(sdRef, flags, interfaceIndex, errorCode, fullname, hosttarget, 1529 port, txtLen, txtRecord, context): 1530 if callBack is not None: 1531 port = socket.ntohs(port) 1532 txtRecord = _length_and_void_p_to_string(txtLen, txtRecord) 1533 callBack(sdRef, flags, interfaceIndex, errorCode, fullname.decode(), 1534 hosttarget.decode(), port, txtRecord) 1535 1536 _global_lock.acquire() 1537 try: 1538 sdRef = _DNSServiceResolve(flags, 1539 interfaceIndex, 1540 name, 1541 regtype, 1542 domain, 1543 _callback, 1544 None) 1545 finally: 1546 _global_lock.release() 1547 1548 sdRef._add_callback(_callback) 1549 1550 return sdRef 1551 1552 1553def DNSServiceCreateConnection(): 1554 1555 """ 1556 1557 Create a connection to the daemon allowing efficient registration 1558 of multiple individual records. 1559 1560 return value: 1561 A DNSServiceRef instance. Closing it severs the connection 1562 and deregisters all records registered on this connection. 1563 1564 """ 1565 1566 _global_lock.acquire() 1567 try: 1568 sdRef = _DNSServiceCreateConnection() 1569 finally: 1570 _global_lock.release() 1571 1572 return sdRef 1573 1574 1575def DNSServiceRegisterRecord( 1576 sdRef, 1577 flags, 1578 interfaceIndex = kDNSServiceInterfaceIndexAny, 1579 fullname = _NO_DEFAULT, 1580 rrtype = _NO_DEFAULT, 1581 rrclass = kDNSServiceClass_IN, 1582 rdata = _NO_DEFAULT, 1583 ttl = 0, 1584 callBack = None, 1585 ): 1586 1587 """ 1588 1589 Register an individual resource record on a connected 1590 DNSServiceRef. 1591 1592 Note that name conflicts occurring for records registered via this 1593 call must be handled by the client in the callback. 1594 1595 sdRef: 1596 A DNSServiceRef returned by DNSServiceCreateConnection(). 1597 1598 flags: 1599 Possible values are kDNSServiceFlagsShared or 1600 kDNSServiceFlagsUnique. 1601 1602 interfaceIndex: 1603 If non-zero, specifies the interface on which to register the 1604 record. Passing kDNSServiceInterfaceIndexAny (0) causes the 1605 record to be registered on all interfaces. 1606 1607 fullname: 1608 The full domain name of the resource record. 1609 1610 rrtype: 1611 The numerical type of the resource record 1612 (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc.). 1613 1614 rrclass: 1615 The class of the resource record (usually 1616 kDNSServiceClass_IN). 1617 1618 rdata: 1619 A string containing the raw rdata, as it is to appear in the 1620 DNS record. 1621 1622 ttl: 1623 The time to live of the resource record, in seconds. Pass 0 1624 to use a default value. 1625 1626 callBack: 1627 The function to be called when a result is found, or if the 1628 call asynchronously fails (e.g. because of a name conflict). 1629 Its signature should be 1630 callBack(sdRef, RecordRef, flags, errorCode). 1631 1632 return value: 1633 A DNSRecordRef instance, which may be passed to 1634 DNSServiceUpdateRecord() or DNSServiceRemoveRecord(). (To 1635 deregister ALL records registered on a single connected 1636 DNSServiceRef and deallocate each of their corresponding 1637 DNSRecordRefs, close the DNSServiceRef.) 1638 1639 Callback Parameters: 1640 1641 sdRef: 1642 The connected DNSServiceRef returned by 1643 DNSServiceCreateConnection(). 1644 1645 RecordRef: 1646 The DNSRecordRef returned by DNSServiceRegisterRecord(). 1647 1648 flags: 1649 Currently unused, reserved for future use. 1650 1651 errorCode: 1652 Will be kDNSServiceErr_NoError on success, otherwise will 1653 indicate the failure that occurred (including name conflicts). 1654 Other parameters are undefined if an error occurred. 1655 1656 """ 1657 1658 _NO_DEFAULT.check(fullname) 1659 _NO_DEFAULT.check(rrtype) 1660 _NO_DEFAULT.check(rdata) 1661 1662 rdlen, rdata = _string_to_length_and_void_p(rdata) 1663 1664 @_DNSServiceRegisterRecordReply 1665 def _callback(sdRef, RecordRef, flags, errorCode, context): 1666 if callBack is not None: 1667 callBack(sdRef, RecordRef, flags, errorCode) 1668 1669 _global_lock.acquire() 1670 try: 1671 RecordRef = _DNSServiceRegisterRecord(sdRef, 1672 flags, 1673 interfaceIndex, 1674 fullname, 1675 rrtype, 1676 rrclass, 1677 rdlen, 1678 rdata, 1679 ttl, 1680 _callback, 1681 None) 1682 finally: 1683 _global_lock.release() 1684 1685 sdRef._add_callback(_callback) 1686 sdRef._add_record_ref(RecordRef) 1687 1688 return RecordRef 1689 1690 1691def DNSServiceQueryRecord( 1692 flags = 0, 1693 interfaceIndex = kDNSServiceInterfaceIndexAny, 1694 fullname = _NO_DEFAULT, 1695 rrtype = _NO_DEFAULT, 1696 rrclass = kDNSServiceClass_IN, 1697 callBack = None, 1698 ): 1699 1700 """ 1701 1702 Query for an arbitrary DNS record. 1703 1704 flags: 1705 Pass kDNSServiceFlagsLongLivedQuery to create a "long-lived" 1706 unicast query in a non-local domain. Without setting this 1707 flag, unicast queries will be one-shot; that is, only answers 1708 available at the time of the call will be returned. By 1709 setting this flag, answers (including Add and Remove events) 1710 that become available after the initial call is made will 1711 generate callbacks. This flag has no effect on link-local 1712 multicast queries. 1713 1714 interfaceIndex: 1715 If non-zero, specifies the interface on which to issue the 1716 query. Passing kDNSServiceInterfaceIndexAny (0) causes the 1717 name to be queried for on all interfaces. 1718 1719 fullname: 1720 The full domain name of the resource record to be queried for. 1721 1722 rrtype: 1723 The numerical type of the resource record to be queried for 1724 (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc.). 1725 1726 rrclass: 1727 The class of the resource record (usually 1728 kDNSServiceClass_IN). 1729 1730 callBack: 1731 The function to be called when a result is found, or if the 1732 call asynchronously fails. Its signature should be 1733 callBack(sdRef, flags, interfaceIndex, errorCode, fullname, 1734 rrtype, rrclass, rdata, ttl). 1735 1736 return value: 1737 A DNSServiceRef instance. The query operation will run 1738 indefinitely until the client terminates it by closing the 1739 DNSServiceRef. 1740 1741 Callback Parameters: 1742 1743 sdRef: 1744 The DNSServiceRef returned by DNSServiceQueryRecord(). 1745 1746 flags: 1747 Possible values are kDNSServiceFlagsMoreComing and 1748 kDNSServiceFlagsAdd. The Add flag is NOT set for PTR records 1749 with a ttl of 0, i.e. "Remove" events. 1750 1751 interfaceIndex: 1752 The interface on which the query was resolved. 1753 1754 errorCode: 1755 Will be kDNSServiceErr_NoError on success, otherwise will 1756 indicate the failure that occurred. Other parameters are 1757 undefined if an error occurred. 1758 1759 fullname: 1760 The resource record's full domain name. 1761 1762 rrtype: 1763 The resource record's type (e.g. kDNSServiceType_PTR, 1764 kDNSServiceType_SRV, etc.). 1765 1766 rrclass: 1767 The class of the resource record (usually 1768 kDNSServiceClass_IN). 1769 1770 rdata: 1771 A string containing the raw rdata of the resource record. 1772 1773 ttl: 1774 The resource record's time to live, in seconds. 1775 1776 """ 1777 1778 _NO_DEFAULT.check(fullname) 1779 _NO_DEFAULT.check(rrtype) 1780 1781 @_DNSServiceQueryRecordReply 1782 def _callback(sdRef, flags, interfaceIndex, errorCode, fullname, rrtype, 1783 rrclass, rdlen, rdata, ttl, context): 1784 if callBack is not None: 1785 rdata = _length_and_void_p_to_string(rdlen, rdata) 1786 callBack(sdRef, flags, interfaceIndex, errorCode, fullname.decode(), 1787 rrtype, rrclass, rdata, ttl) 1788 1789 _global_lock.acquire() 1790 try: 1791 sdRef = _DNSServiceQueryRecord(flags, 1792 interfaceIndex, 1793 fullname, 1794 rrtype, 1795 rrclass, 1796 _callback, 1797 None) 1798 finally: 1799 _global_lock.release() 1800 1801 sdRef._add_callback(_callback) 1802 1803 return sdRef 1804 1805 1806def DNSServiceReconfirmRecord( 1807 flags = 0, 1808 interfaceIndex = kDNSServiceInterfaceIndexAny, 1809 fullname = _NO_DEFAULT, 1810 rrtype = _NO_DEFAULT, 1811 rrclass = kDNSServiceClass_IN, 1812 rdata = _NO_DEFAULT, 1813 ): 1814 1815 """ 1816 1817 Instruct the daemon to verify the validity of a resource record 1818 that appears to be out of date (e.g. because tcp connection to a 1819 service's target failed). Causes the record to be flushed from 1820 the daemon's cache (as well as all other daemons' caches on the 1821 network) if the record is determined to be invalid. 1822 1823 flags: 1824 Currently unused, reserved for future use. 1825 1826 interfaceIndex: 1827 If non-zero, specifies the interface of the record in 1828 question. Passing kDNSServiceInterfaceIndexAny (0) causes all 1829 instances of this record to be reconfirmed. 1830 1831 fullname: 1832 The resource record's full domain name. 1833 1834 rrtype: 1835 The resource record's type (e.g. kDNSServiceType_PTR, 1836 kDNSServiceType_SRV, etc.). 1837 1838 rrclass: 1839 The class of the resource record (usually 1840 kDNSServiceClass_IN). 1841 1842 rdata: 1843 A string containing the raw rdata of the resource record. 1844 1845 """ 1846 1847 _NO_DEFAULT.check(fullname) 1848 _NO_DEFAULT.check(rrtype) 1849 _NO_DEFAULT.check(rdata) 1850 1851 rdlen, rdata = _string_to_length_and_void_p(rdata) 1852 1853 _global_lock.acquire() 1854 try: 1855 _DNSServiceReconfirmRecord(flags, 1856 interfaceIndex, 1857 fullname, 1858 rrtype, 1859 rrclass, 1860 rdlen, 1861 rdata) 1862 finally: 1863 _global_lock.release() 1864 1865 1866def DNSServiceConstructFullName( 1867 service = None, 1868 regtype = _NO_DEFAULT, 1869 domain = _NO_DEFAULT, 1870 ): 1871 1872 """ 1873 1874 Concatenate a three-part domain name (as returned by a callback 1875 function) into a properly-escaped full domain name. Note that 1876 callback functions already escape strings where necessary. 1877 1878 service: 1879 The service name; any dots or backslashes must NOT be escaped. 1880 May be None (to construct a PTR record name, e.g. 1881 "_ftp._tcp.apple.com."). 1882 1883 regtype: 1884 The service type followed by the protocol, separated by a dot 1885 (e.g. "_ftp._tcp"). 1886 1887 domain: 1888 The domain name, e.g. "apple.com.". Literal dots or 1889 backslashes, if any, must be escaped, 1890 e.g. "1st\. Floor.apple.com." 1891 1892 return value: 1893 The resulting full domain name. 1894 1895 """ 1896 1897 _NO_DEFAULT.check(regtype) 1898 _NO_DEFAULT.check(domain) 1899 1900 _global_lock.acquire() 1901 try: 1902 fullName = _DNSServiceConstructFullName(service, regtype, domain) 1903 finally: 1904 _global_lock.release() 1905 1906 return fullName.value.decode('utf-8') 1907 1908 1909 1910################################################################################ 1911# 1912# TXTRecord class 1913# 1914################################################################################ 1915 1916 1917 1918class TXTRecord(object): 1919 1920 """ 1921 1922 A mapping representing a DNS TXT record. The TXT record's 1923 name=value entries are stored as key/value pairs in the mapping. 1924 Although keys can be accessed in a case-insensitive fashion 1925 (meaning txt['foo'] and txt['FoO'] refer to the same value), key 1926 case is preserved in the wire representation of the record (so 1927 txt['FoO'] = 'bar' will generate a FoO=bar entry in the TXT 1928 record). Key order is also preserved, so keys appear in the wire 1929 format in the order in which they were created. 1930 1931 Note that in addition to being valid as a txtRecord parameter to 1932 DNSServiceRegister(), a TXTRecord instance can be used in place of 1933 a resource record data string (i.e. rdata parameter) with any 1934 function that accepts one. 1935 1936 """ 1937 1938 def __init__(self, items={}, strict=True): 1939 """ 1940 1941 Create a new TXTRecord instance, initializing it with the 1942 contents of items. If strict is true, then strict conformance 1943 to the DNS TXT record format will be enforced, and attempts to 1944 add a name containing invalid characters or a name/value pair 1945 whose wire representation is longer than 255 bytes will raise 1946 a ValueError exception. 1947 1948 """ 1949 1950 self.strict = strict 1951 self._names = [] 1952 self._items = {} 1953 1954 for name, value in items.items(): 1955 self[name] = value 1956 1957 def __contains__(self, name): 1958 'Return True if name is a key in the record, False otherwise' 1959 return (name.lower() in self._items) 1960 1961 def __iter__(self): 1962 'Return an iterator over name/value pairs' 1963 for name in self._names: 1964 yield self._items[name] 1965 1966 def __len__(self): 1967 'Return the number of name/value pairs' 1968 return len(self._names) 1969 1970 def __nonzero__(self): 1971 'Return False if the record is empty, True otherwise' 1972 return bool(self._items) 1973 1974 def __str__(self): 1975 """ 1976 1977 Return the wire representation of the TXT record as a string. 1978 If self.strict is false, any name/value pair whose wire length 1979 if greater than 255 bytes will be truncated to 255 bytes. If 1980 the record is empty, '\\0' is returned. 1981 1982 """ 1983 1984 if not self: 1985 return '\0' 1986 1987 parts = [] 1988 for name, value in self: 1989 if value is None: 1990 item = name 1991 else: 1992 item = '%s=%s' % (name, value) 1993 if (not self.strict) and (len(item) > 255): 1994 item = item[:255] 1995 parts.append(chr(len(item))) 1996 parts.append(item) 1997 1998 return ''.join(parts) 1999 2000 def __getitem__(self, name): 2001 """ 2002 2003 Return the value associated with name. The value is either 2004 None (meaning name has no associated value) or an str instance 2005 (which may be of length 0). Raises KeyError if name is not a 2006 key. 2007 2008 """ 2009 return self._items[name.lower()][1] 2010 2011 # Require one or more printable ASCII characters (0x20-0x7E), 2012 # excluding '=' (0x3D) 2013 _valid_name_re = re.compile(r'^[ -<>-~]+$') 2014 2015 def __setitem__(self, name, value): 2016 """ 2017 2018 Add a name/value pair to the record. If value is None, then 2019 name will have no associated value. If value is a unicode 2020 instance, it will be encoded as a UTF-8 string. Otherwise, 2021 value will be converted to an str instance. 2022 2023 """ 2024 2025 stored_name = name 2026 name = name.lower() 2027 length = len(name) 2028 2029 if value is not None: 2030 value = str(value) 2031 length += 1 + len(value) 2032 2033 if self.strict and (length > 255): 2034 raise ValueError('name=value string must be 255 bytes or less') 2035 2036 if name not in self._items: 2037 if self.strict and (self._valid_name_re.match(stored_name) is None): 2038 raise ValueError("invalid name: '%s'" % stored_name) 2039 self._names.append(name) 2040 2041 self._items[name] = (stored_name, value) 2042 2043 def __delitem__(self, name): 2044 """ 2045 2046 Remove name and its corresponding value from the record. 2047 Raises KeyError if name is not a key. 2048 2049 """ 2050 name = name.lower() 2051 del self._items[name] 2052 self._names.remove(name) 2053 2054 @classmethod 2055 def parse(cls, data, strict=False): 2056 """ 2057 2058 Given a string data containing the wire representation of a 2059 DNS TXT record, parse it and return a TXTRecord instance. The 2060 strict parameter is passed to the TXTRecord constructor. 2061 2062 """ 2063 2064 txt = cls(strict=strict) 2065 2066 while data: 2067 length = ord(data[0]) 2068 item = data[1:length+1].split('=', 1) 2069 2070 # Add the item only if the name is non-empty and there are 2071 # no existing items with the same name 2072 if item[0] and (item[0] not in txt): 2073 if len(item) == 1: 2074 txt[item[0]] = None 2075 else: 2076 txt[item[0]] = item[1] 2077 2078 data = data[length+1:] 2079 2080 return txt 2081