hgext/zeroconf/Zeroconf.py
author Boris Feld <boris.feld@octobus.net>
Thu, 07 Dec 2017 18:55:35 +0100
changeset 35351 75520786ad2f
parent 34448 5385b76fd1fd
child 35629 31451f3f4b56
permissions -rw-r--r--
upgrade: use the repository 'ui' as the base for the new repository The `repo.baseui` contains all the configuration but the one specific to the repository (so it can be used when dealing with local peer and sub- repository). However, we need the repository config to be taken into account when doing the upgrade. Otherwise, the upgrade related config that exists in the repository config won't be taken into account when performing the update. A buggy and surprising behavior. We had to work around protection set around `repo.ui.copy` since we are an uncommon case.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
28296
a73394e7b47c zeroconf: use absolute_import
timeless <timeless@mozdev.org>
parents: 28295
diff changeset
     1
from __future__ import absolute_import, print_function
28295
01815c159856 zeroconf: use print function
timeless <timeless@mozdev.org>
parents: 28249
diff changeset
     2
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     3
""" Multicast DNS Service Discovery for Python, v0.12
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     4
    Copyright (C) 2003, Paul Scott-Murphy
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     5
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     6
    This module provides a framework for the use of DNS Service Discovery
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     7
    using IP multicast.  It has been tested against the JRendezvous
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     8
    implementation from <a href="http://strangeberry.com">StrangeBerry</a>,
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     9
    and against the mDNSResponder from Mac OS X 10.3.8.
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    10
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    11
    This library is free software; you can redistribute it and/or
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    12
    modify it under the terms of the GNU Lesser General Public
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    13
    License as published by the Free Software Foundation; either
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    14
    version 2.1 of the License, or (at your option) any later version.
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    15
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    16
    This library is distributed in the hope that it will be useful,
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    17
    but WITHOUT ANY WARRANTY; without even the implied warranty of
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    18
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    19
    Lesser General Public License for more details.
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    20
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    21
    You should have received a copy of the GNU Lesser General Public
15782
7de7630053cb Remove FSF mailing address from GPL headers
Martin Geisler <mg@aragost.com>
parents: 14494
diff changeset
    22
    License along with this library; if not, see
7de7630053cb Remove FSF mailing address from GPL headers
Martin Geisler <mg@aragost.com>
parents: 14494
diff changeset
    23
    <http://www.gnu.org/licenses/>.
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
    24
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    25
"""
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    26
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    27
"""0.12 update - allow selection of binding interface
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
    28
         typo fix - Thanks A. M. Kuchlingi
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
    29
         removed all use of word 'Rendezvous' - this is an API change"""
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    30
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    31
"""0.11 update - correction to comments for addListener method
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    32
                 support for new record types seen from OS X
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
    33
                  - IPv6 address
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
    34
                  - hostinfo
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
    35
                 ignore unknown DNS record types
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
    36
                 fixes to name decoding
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
    37
                 works alongside other processes using port 5353 (e.g. Mac OS X)
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
    38
                 tested against Mac OS X 10.3.2's mDNSResponder
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
    39
                 corrections to removal of list entries for service browser"""
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    40
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    41
"""0.10 update - Jonathon Paisley contributed these corrections:
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    42
                 always multicast replies, even when query is unicast
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
    43
                 correct a pointer encoding problem
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
    44
                 can now write records in any order
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
    45
                 traceback shown on failure
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
    46
                 better TXT record parsing
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
    47
                 server is now separate from name
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
    48
                 can cancel a service browser
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    49
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
    50
                 modified some unit tests to accommodate these changes"""
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    51
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    52
"""0.09 update - remove all records on service unregistration
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    53
                 fix DOS security problem with readName"""
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    54
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    55
"""0.08 update - changed licensing to LGPL"""
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    56
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    57
"""0.07 update - faster shutdown on engine
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    58
                 pointer encoding of outgoing names
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
    59
                 ServiceBrowser now works
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
    60
                 new unit tests"""
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    61
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    62
"""0.06 update - small improvements with unit tests
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    63
                 added defined exception types
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
    64
                 new style objects
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
    65
                 fixed hostname/interface problem
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
    66
                 fixed socket timeout problem
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
    67
                 fixed addServiceListener() typo bug
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
    68
                 using select() for socket reads
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
    69
                 tested on Debian unstable with Python 2.2.2"""
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    70
17424
e7cfe3587ea4 fix trivial spelling errors
Mads Kiilerich <mads@kiilerich.com>
parents: 15782
diff changeset
    71
"""0.05 update - ensure case insensitivity on domain names
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    72
                 support for unicast DNS queries"""
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    73
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    74
"""0.04 update - added some unit tests
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    75
                 added __ne__ adjuncts where required
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
    76
                 ensure names end in '.local.'
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
    77
                 timeout on receiving socket for clean shutdown"""
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    78
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    79
__author__ = "Paul Scott-Murphy"
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    80
__email__ = "paul at scott dash murphy dot com"
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    81
__version__ = "0.12"
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    82
34448
5385b76fd1fd zeroconf: do not crash if socket being read is closed by another thread
Jun Wu <quark@fb.com>
parents: 28504
diff changeset
    83
import errno
28422
e2c6092ad422 zeroconf: replace reduce+add with itertools.chain
timeless <timeless@mozdev.org>
parents: 28421
diff changeset
    84
import itertools
28296
a73394e7b47c zeroconf: use absolute_import
timeless <timeless@mozdev.org>
parents: 28295
diff changeset
    85
import select
a73394e7b47c zeroconf: use absolute_import
timeless <timeless@mozdev.org>
parents: 28295
diff changeset
    86
import socket
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    87
import string
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    88
import struct
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    89
import threading
28296
a73394e7b47c zeroconf: use absolute_import
timeless <timeless@mozdev.org>
parents: 28295
diff changeset
    90
import time
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    91
import traceback
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    92
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    93
__all__ = ["Zeroconf", "ServiceInfo", "ServiceBrowser"]
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    94
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    95
# hook for threads
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    96
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    97
globals()['_GLOBAL_DONE'] = 0
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    98
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    99
# Some timing constants
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   100
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   101
_UNREGISTER_TIME = 125
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   102
_CHECK_TIME = 175
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   103
_REGISTER_TIME = 225
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   104
_LISTENER_TIME = 200
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   105
_BROWSER_TIME = 500
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   106
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   107
# Some DNS constants
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
   108
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   109
_MDNS_ADDR = '224.0.0.251'
28297
f6d07520c665 zeroconf: omit semicolons
timeless <timeless@mozdev.org>
parents: 28296
diff changeset
   110
_MDNS_PORT = 5353
f6d07520c665 zeroconf: omit semicolons
timeless <timeless@mozdev.org>
parents: 28296
diff changeset
   111
_DNS_PORT = 53
f6d07520c665 zeroconf: omit semicolons
timeless <timeless@mozdev.org>
parents: 28296
diff changeset
   112
_DNS_TTL = 60 * 60 # one hour default TTL
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   113
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   114
_MAX_MSG_TYPICAL = 1460 # unused
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   115
_MAX_MSG_ABSOLUTE = 8972
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   116
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   117
_FLAGS_QR_MASK = 0x8000 # query response mask
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   118
_FLAGS_QR_QUERY = 0x0000 # query
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   119
_FLAGS_QR_RESPONSE = 0x8000 # response
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   120
17476
210acc861c40 spelling: Authoritative
timeless@mozdev.org
parents: 15782
diff changeset
   121
_FLAGS_AA = 0x0400 # Authoritative answer
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   122
_FLAGS_TC = 0x0200 # Truncated
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   123
_FLAGS_RD = 0x0100 # Recursion desired
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   124
_FLAGS_RA = 0x8000 # Recursion available
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   125
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   126
_FLAGS_Z = 0x0040 # Zero
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   127
_FLAGS_AD = 0x0020 # Authentic data
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   128
_FLAGS_CD = 0x0010 # Checking disabled
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   129
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   130
_CLASS_IN = 1
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   131
_CLASS_CS = 2
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   132
_CLASS_CH = 3
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   133
_CLASS_HS = 4
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   134
_CLASS_NONE = 254
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   135
_CLASS_ANY = 255
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   136
_CLASS_MASK = 0x7FFF
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   137
_CLASS_UNIQUE = 0x8000
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   138
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   139
_TYPE_A = 1
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   140
_TYPE_NS = 2
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   141
_TYPE_MD = 3
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   142
_TYPE_MF = 4
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   143
_TYPE_CNAME = 5
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   144
_TYPE_SOA = 6
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   145
_TYPE_MB = 7
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   146
_TYPE_MG = 8
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   147
_TYPE_MR = 9
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   148
_TYPE_NULL = 10
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   149
_TYPE_WKS = 11
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   150
_TYPE_PTR = 12
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   151
_TYPE_HINFO = 13
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   152
_TYPE_MINFO = 14
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   153
_TYPE_MX = 15
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   154
_TYPE_TXT = 16
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   155
_TYPE_AAAA = 28
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   156
_TYPE_SRV = 33
27637
b502138f5faa cleanup: remove superfluous space after space after equals (python)
timeless <timeless@mozdev.org>
parents: 17537
diff changeset
   157
_TYPE_ANY = 255
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   158
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   159
# Mapping constants to names
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   160
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   161
_CLASSES = { _CLASS_IN : "in",
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   162
             _CLASS_CS : "cs",
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   163
             _CLASS_CH : "ch",
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   164
             _CLASS_HS : "hs",
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   165
             _CLASS_NONE : "none",
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   166
             _CLASS_ANY : "any" }
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   167
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   168
_TYPES = { _TYPE_A : "a",
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   169
           _TYPE_NS : "ns",
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   170
           _TYPE_MD : "md",
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   171
           _TYPE_MF : "mf",
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   172
           _TYPE_CNAME : "cname",
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   173
           _TYPE_SOA : "soa",
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   174
           _TYPE_MB : "mb",
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   175
           _TYPE_MG : "mg",
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   176
           _TYPE_MR : "mr",
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   177
           _TYPE_NULL : "null",
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   178
           _TYPE_WKS : "wks",
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   179
           _TYPE_PTR : "ptr",
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   180
           _TYPE_HINFO : "hinfo",
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   181
           _TYPE_MINFO : "minfo",
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   182
           _TYPE_MX : "mx",
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   183
           _TYPE_TXT : "txt",
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   184
           _TYPE_AAAA : "quada",
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   185
           _TYPE_SRV : "srv",
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   186
           _TYPE_ANY : "any" }
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   187
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   188
# utility functions
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   189
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   190
def currentTimeMillis():
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   191
    """Current system time in milliseconds"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   192
    return time.time() * 1000
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   193
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   194
# Exceptions
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   195
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   196
class NonLocalNameException(Exception):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   197
    pass
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   198
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   199
class NonUniqueNameException(Exception):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   200
    pass
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   201
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   202
class NamePartTooLongException(Exception):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   203
    pass
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   204
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   205
class AbstractMethodException(Exception):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   206
    pass
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   207
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   208
class BadTypeInNameException(Exception):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   209
    pass
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   210
11435
7c58cde598fe zeroconf: Use BadDomainName exception instead of string exceptions
Javi Merino <cibervicho@gmail.com>
parents: 10514
diff changeset
   211
class BadDomainName(Exception):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   212
    def __init__(self, pos):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   213
        Exception.__init__(self, "at position %s" % pos)
11435
7c58cde598fe zeroconf: Use BadDomainName exception instead of string exceptions
Javi Merino <cibervicho@gmail.com>
parents: 10514
diff changeset
   214
7c58cde598fe zeroconf: Use BadDomainName exception instead of string exceptions
Javi Merino <cibervicho@gmail.com>
parents: 10514
diff changeset
   215
class BadDomainNameCircular(BadDomainName):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   216
    pass
11435
7c58cde598fe zeroconf: Use BadDomainName exception instead of string exceptions
Javi Merino <cibervicho@gmail.com>
parents: 10514
diff changeset
   217
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   218
# implementation classes
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   219
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   220
class DNSEntry(object):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   221
    """A DNS entry"""
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
   222
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   223
    def __init__(self, name, type, clazz):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   224
        self.key = string.lower(name)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   225
        self.name = name
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   226
        self.type = type
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   227
        self.clazz = clazz & _CLASS_MASK
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   228
        self.unique = (clazz & _CLASS_UNIQUE) != 0
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   229
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   230
    def __eq__(self, other):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   231
        """Equality test on name, type, and class"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   232
        if isinstance(other, DNSEntry):
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   233
            return (self.name == other.name and self.type == other.type and
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   234
                    self.clazz == other.clazz)
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   235
        return 0
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   236
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   237
    def __ne__(self, other):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   238
        """Non-equality test"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   239
        return not self.__eq__(other)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   240
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   241
    def getClazz(self, clazz):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   242
        """Class accessor"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   243
        try:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   244
            return _CLASSES[clazz]
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   245
        except KeyError:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   246
            return "?(%s)" % (clazz)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   247
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   248
    def getType(self, type):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   249
        """Type accessor"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   250
        try:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   251
            return _TYPES[type]
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   252
        except KeyError:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   253
            return "?(%s)" % (type)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   254
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   255
    def toString(self, hdr, other):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   256
        """String representation with additional information"""
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   257
        result = ("%s[%s,%s" %
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   258
            (hdr, self.getType(self.type), self.getClazz(self.clazz)))
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   259
        if self.unique:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   260
            result += "-unique,"
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   261
        else:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   262
            result += ","
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   263
        result += self.name
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   264
        if other is not None:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   265
            result += ",%s]" % (other)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   266
        else:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   267
            result += "]"
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   268
        return result
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   269
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   270
class DNSQuestion(DNSEntry):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   271
    """A DNS question entry"""
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
   272
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   273
    def __init__(self, name, type, clazz):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   274
        if not name.endswith(".local."):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   275
            raise NonLocalNameException(name)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   276
        DNSEntry.__init__(self, name, type, clazz)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   277
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   278
    def answeredBy(self, rec):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   279
        """Returns true if the question is answered by the record"""
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   280
        return (self.clazz == rec.clazz and
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   281
                (self.type == rec.type or self.type == _TYPE_ANY) and
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   282
                self.name == rec.name)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   283
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   284
    def __repr__(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   285
        """String representation"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   286
        return DNSEntry.toString(self, "question", None)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   287
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   288
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   289
class DNSRecord(DNSEntry):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   290
    """A DNS record - like a DNS entry, but has a TTL"""
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
   291
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   292
    def __init__(self, name, type, clazz, ttl):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   293
        DNSEntry.__init__(self, name, type, clazz)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   294
        self.ttl = ttl
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   295
        self.created = currentTimeMillis()
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   296
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   297
    def __eq__(self, other):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   298
        """Tests equality as per DNSRecord"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   299
        if isinstance(other, DNSRecord):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   300
            return DNSEntry.__eq__(self, other)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   301
        return 0
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   302
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   303
    def suppressedBy(self, msg):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   304
        """Returns true if any answer in a message can suffice for the
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   305
        information held in this record."""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   306
        for record in msg.answers:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   307
            if self.suppressedByAnswer(record):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   308
                return 1
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   309
        return 0
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   310
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   311
    def suppressedByAnswer(self, other):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   312
        """Returns true if another record has same name, type and class,
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   313
        and if its TTL is at least half of this record's."""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   314
        if self == other and other.ttl > (self.ttl / 2):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   315
            return 1
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   316
        return 0
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   317
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   318
    def getExpirationTime(self, percent):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   319
        """Returns the time at which this record will have expired
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   320
        by a certain percentage."""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   321
        return self.created + (percent * self.ttl * 10)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   322
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   323
    def getRemainingTTL(self, now):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   324
        """Returns the remaining TTL in seconds."""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   325
        return max(0, (self.getExpirationTime(100) - now) / 1000)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   326
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   327
    def isExpired(self, now):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   328
        """Returns true if this record has expired."""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   329
        return self.getExpirationTime(100) <= now
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   330
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   331
    def isStale(self, now):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   332
        """Returns true if this record is at least half way expired."""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   333
        return self.getExpirationTime(50) <= now
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   334
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   335
    def resetTTL(self, other):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   336
        """Sets this record's TTL and created time to that of
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   337
        another record."""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   338
        self.created = other.created
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   339
        self.ttl = other.ttl
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   340
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   341
    def write(self, out):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   342
        """Abstract method"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   343
        raise AbstractMethodException
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   344
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   345
    def toString(self, other):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   346
        """String representation with additional information"""
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   347
        arg = ("%s/%s,%s" %
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   348
            (self.ttl, self.getRemainingTTL(currentTimeMillis()), other))
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   349
        return DNSEntry.toString(self, "record", arg)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   350
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   351
class DNSAddress(DNSRecord):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   352
    """A DNS address record"""
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
   353
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   354
    def __init__(self, name, type, clazz, ttl, address):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   355
        DNSRecord.__init__(self, name, type, clazz, ttl)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   356
        self.address = address
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   357
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   358
    def write(self, out):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   359
        """Used in constructing an outgoing packet"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   360
        out.writeString(self.address, len(self.address))
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   361
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   362
    def __eq__(self, other):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   363
        """Tests equality on address"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   364
        if isinstance(other, DNSAddress):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   365
            return self.address == other.address
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   366
        return 0
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   367
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   368
    def __repr__(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   369
        """String representation"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   370
        try:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   371
            return socket.inet_ntoa(self.address)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   372
        except Exception:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   373
            return self.address
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   374
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   375
class DNSHinfo(DNSRecord):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   376
    """A DNS host information record"""
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   377
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   378
    def __init__(self, name, type, clazz, ttl, cpu, os):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   379
        DNSRecord.__init__(self, name, type, clazz, ttl)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   380
        self.cpu = cpu
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   381
        self.os = os
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   382
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   383
    def write(self, out):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   384
        """Used in constructing an outgoing packet"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   385
        out.writeString(self.cpu, len(self.cpu))
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   386
        out.writeString(self.os, len(self.os))
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   387
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   388
    def __eq__(self, other):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   389
        """Tests equality on cpu and os"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   390
        if isinstance(other, DNSHinfo):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   391
            return self.cpu == other.cpu and self.os == other.os
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   392
        return 0
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   393
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   394
    def __repr__(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   395
        """String representation"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   396
        return self.cpu + " " + self.os
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
   397
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   398
class DNSPointer(DNSRecord):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   399
    """A DNS pointer record"""
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
   400
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   401
    def __init__(self, name, type, clazz, ttl, alias):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   402
        DNSRecord.__init__(self, name, type, clazz, ttl)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   403
        self.alias = alias
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   404
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   405
    def write(self, out):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   406
        """Used in constructing an outgoing packet"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   407
        out.writeName(self.alias)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   408
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   409
    def __eq__(self, other):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   410
        """Tests equality on alias"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   411
        if isinstance(other, DNSPointer):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   412
            return self.alias == other.alias
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   413
        return 0
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   414
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   415
    def __repr__(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   416
        """String representation"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   417
        return self.toString(self.alias)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   418
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   419
class DNSText(DNSRecord):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   420
    """A DNS text record"""
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
   421
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   422
    def __init__(self, name, type, clazz, ttl, text):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   423
        DNSRecord.__init__(self, name, type, clazz, ttl)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   424
        self.text = text
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   425
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   426
    def write(self, out):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   427
        """Used in constructing an outgoing packet"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   428
        out.writeString(self.text, len(self.text))
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   429
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   430
    def __eq__(self, other):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   431
        """Tests equality on text"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   432
        if isinstance(other, DNSText):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   433
            return self.text == other.text
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   434
        return 0
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   435
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   436
    def __repr__(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   437
        """String representation"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   438
        if len(self.text) > 10:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   439
            return self.toString(self.text[:7] + "...")
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   440
        else:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   441
            return self.toString(self.text)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   442
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   443
class DNSService(DNSRecord):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   444
    """A DNS service record"""
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
   445
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   446
    def __init__(self, name, type, clazz, ttl, priority, weight, port, server):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   447
        DNSRecord.__init__(self, name, type, clazz, ttl)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   448
        self.priority = priority
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   449
        self.weight = weight
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   450
        self.port = port
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   451
        self.server = server
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   452
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   453
    def write(self, out):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   454
        """Used in constructing an outgoing packet"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   455
        out.writeShort(self.priority)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   456
        out.writeShort(self.weight)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   457
        out.writeShort(self.port)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   458
        out.writeName(self.server)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   459
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   460
    def __eq__(self, other):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   461
        """Tests equality on priority, weight, port and server"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   462
        if isinstance(other, DNSService):
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   463
            return (self.priority == other.priority and
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   464
                    self.weight == other.weight and
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   465
                    self.port == other.port and
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   466
                    self.server == other.server)
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   467
        return 0
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   468
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   469
    def __repr__(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   470
        """String representation"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   471
        return self.toString("%s:%s" % (self.server, self.port))
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   472
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   473
class DNSIncoming(object):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   474
    """Object representation of an incoming DNS packet"""
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
   475
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   476
    def __init__(self, data):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   477
        """Constructor from string holding bytes of packet"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   478
        self.offset = 0
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   479
        self.data = data
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   480
        self.questions = []
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   481
        self.answers = []
28419
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
   482
        self.numquestions = 0
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
   483
        self.numanswers = 0
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
   484
        self.numauthorities = 0
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
   485
        self.numadditionals = 0
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
   486
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   487
        self.readHeader()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   488
        self.readQuestions()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   489
        self.readOthers()
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   490
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   491
    def readHeader(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   492
        """Reads header portion of packet"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   493
        format = '!HHHHHH'
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   494
        length = struct.calcsize(format)
28300
15c5f50e7e13 zeroconf: add whitespace around operator
timeless <timeless@mozdev.org>
parents: 28299
diff changeset
   495
        info = struct.unpack(format,
15c5f50e7e13 zeroconf: add whitespace around operator
timeless <timeless@mozdev.org>
parents: 28299
diff changeset
   496
                             self.data[self.offset:self.offset + length])
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   497
        self.offset += length
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   498
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   499
        self.id = info[0]
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   500
        self.flags = info[1]
28419
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
   501
        self.numquestions = info[2]
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
   502
        self.numanswers = info[3]
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
   503
        self.numauthorities = info[4]
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
   504
        self.numadditionals = info[5]
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   505
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   506
    def readQuestions(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   507
        """Reads questions section of packet"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   508
        format = '!HH'
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   509
        length = struct.calcsize(format)
28419
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
   510
        for i in range(0, self.numquestions):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   511
            name = self.readName()
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   512
            info = struct.unpack(format,
28300
15c5f50e7e13 zeroconf: add whitespace around operator
timeless <timeless@mozdev.org>
parents: 28299
diff changeset
   513
                                 self.data[self.offset:self.offset + length])
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   514
            self.offset += length
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
   515
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   516
            try:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   517
                question = DNSQuestion(name, info[0], info[1])
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   518
                self.questions.append(question)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   519
            except NonLocalNameException:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   520
                pass
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   521
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   522
    def readInt(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   523
        """Reads an integer from the packet"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   524
        format = '!I'
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   525
        length = struct.calcsize(format)
28300
15c5f50e7e13 zeroconf: add whitespace around operator
timeless <timeless@mozdev.org>
parents: 28299
diff changeset
   526
        info = struct.unpack(format,
15c5f50e7e13 zeroconf: add whitespace around operator
timeless <timeless@mozdev.org>
parents: 28299
diff changeset
   527
                             self.data[self.offset:self.offset + length])
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   528
        self.offset += length
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   529
        return info[0]
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   530
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   531
    def readCharacterString(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   532
        """Reads a character string from the packet"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   533
        length = ord(self.data[self.offset])
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   534
        self.offset += 1
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   535
        return self.readString(length)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   536
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   537
    def readString(self, len):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   538
        """Reads a string of a given length from the packet"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   539
        format = '!' + str(len) + 's'
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   540
        length = struct.calcsize(format)
28300
15c5f50e7e13 zeroconf: add whitespace around operator
timeless <timeless@mozdev.org>
parents: 28299
diff changeset
   541
        info = struct.unpack(format,
15c5f50e7e13 zeroconf: add whitespace around operator
timeless <timeless@mozdev.org>
parents: 28299
diff changeset
   542
                             self.data[self.offset:self.offset + length])
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   543
        self.offset += length
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   544
        return info[0]
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   545
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   546
    def readUnsignedShort(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   547
        """Reads an unsigned short from the packet"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   548
        format = '!H'
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   549
        length = struct.calcsize(format)
28300
15c5f50e7e13 zeroconf: add whitespace around operator
timeless <timeless@mozdev.org>
parents: 28299
diff changeset
   550
        info = struct.unpack(format,
15c5f50e7e13 zeroconf: add whitespace around operator
timeless <timeless@mozdev.org>
parents: 28299
diff changeset
   551
                             self.data[self.offset:self.offset + length])
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   552
        self.offset += length
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   553
        return info[0]
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   554
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   555
    def readOthers(self):
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   556
        """Reads answers, authorities and additionals section of the packet"""
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   557
        format = '!HHiH'
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   558
        length = struct.calcsize(format)
28504
3c90090320ad zeroconf: remove leftover camelcase identifier
Martin von Zweigbergk <martinvonz@google.com>
parents: 28422
diff changeset
   559
        n = self.numanswers + self.numauthorities + self.numadditionals
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   560
        for i in range(0, n):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   561
            domain = self.readName()
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   562
            info = struct.unpack(format,
28300
15c5f50e7e13 zeroconf: add whitespace around operator
timeless <timeless@mozdev.org>
parents: 28299
diff changeset
   563
                                 self.data[self.offset:self.offset + length])
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   564
            self.offset += length
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   565
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   566
            rec = None
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   567
            if info[0] == _TYPE_A:
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   568
                rec = DNSAddress(domain, info[0], info[1], info[2],
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   569
                                 self.readString(4))
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   570
            elif info[0] == _TYPE_CNAME or info[0] == _TYPE_PTR:
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   571
                rec = DNSPointer(domain, info[0], info[1], info[2],
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   572
                                 self.readName())
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   573
            elif info[0] == _TYPE_TXT:
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   574
                rec = DNSText(domain, info[0], info[1], info[2],
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   575
                              self.readString(info[3]))
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   576
            elif info[0] == _TYPE_SRV:
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   577
                rec = DNSService(domain, info[0], info[1], info[2],
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   578
                                 self.readUnsignedShort(),
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   579
                                 self.readUnsignedShort(),
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   580
                                 self.readUnsignedShort(),
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   581
                                 self.readName())
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   582
            elif info[0] == _TYPE_HINFO:
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   583
                rec = DNSHinfo(domain, info[0], info[1], info[2],
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   584
                               self.readCharacterString(),
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   585
                               self.readCharacterString())
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   586
            elif info[0] == _TYPE_AAAA:
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   587
                rec = DNSAddress(domain, info[0], info[1], info[2],
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
   588
                                 self.readString(16))
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   589
            else:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   590
                # Try to ignore types we don't know about
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   591
                # this may mean the rest of the name is
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   592
                # unable to be parsed, and may show errors
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   593
                # so this is left for debugging.  New types
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   594
                # encountered need to be parsed properly.
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   595
                #
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   596
                #print "UNKNOWN TYPE = " + str(info[0])
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   597
                #raise BadTypeInNameException
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   598
                self.offset += info[3]
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   599
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   600
            if rec is not None:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   601
                self.answers.append(rec)
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
   602
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   603
    def isQuery(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   604
        """Returns true if this is a query"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   605
        return (self.flags & _FLAGS_QR_MASK) == _FLAGS_QR_QUERY
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   606
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   607
    def isResponse(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   608
        """Returns true if this is a response"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   609
        return (self.flags & _FLAGS_QR_MASK) == _FLAGS_QR_RESPONSE
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   610
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   611
    def readUTF(self, offset, len):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   612
        """Reads a UTF-8 string of a given length from the packet"""
28300
15c5f50e7e13 zeroconf: add whitespace around operator
timeless <timeless@mozdev.org>
parents: 28299
diff changeset
   613
        return self.data[offset:offset + len].decode('utf-8')
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
   614
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   615
    def readName(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   616
        """Reads a domain name from the packet"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   617
        result = ''
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   618
        off = self.offset
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   619
        next = -1
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   620
        first = off
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   621
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   622
        while True:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   623
            len = ord(self.data[off])
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   624
            off += 1
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   625
            if len == 0:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   626
                break
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   627
            t = len & 0xC0
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   628
            if t == 0x00:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   629
                result = ''.join((result, self.readUTF(off, len) + '.'))
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   630
                off += len
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   631
            elif t == 0xC0:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   632
                if next < 0:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   633
                    next = off + 1
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   634
                off = ((len & 0x3F) << 8) | ord(self.data[off])
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   635
                if off >= first:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   636
                    raise BadDomainNameCircular(off)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   637
                first = off
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   638
            else:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   639
                raise BadDomainName(off)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   640
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   641
        if next >= 0:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   642
            self.offset = next
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   643
        else:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   644
            self.offset = off
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   645
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   646
        return result
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
   647
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
   648
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   649
class DNSOutgoing(object):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   650
    """Object representation of an outgoing packet"""
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
   651
28302
e96a3ae025ed zeroconf: remove whitespace around = for named parameters
timeless <timeless@mozdev.org>
parents: 28301
diff changeset
   652
    def __init__(self, flags, multicast=1):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   653
        self.finished = 0
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   654
        self.id = 0
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   655
        self.multicast = multicast
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   656
        self.flags = flags
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   657
        self.names = {}
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   658
        self.data = []
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   659
        self.size = 12
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
   660
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   661
        self.questions = []
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   662
        self.answers = []
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   663
        self.authorities = []
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   664
        self.additionals = []
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   665
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   666
    def addQuestion(self, record):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   667
        """Adds a question"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   668
        self.questions.append(record)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   669
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   670
    def addAnswer(self, inp, record):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   671
        """Adds an answer"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   672
        if not record.suppressedBy(inp):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   673
            self.addAnswerAtTime(record, 0)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   674
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   675
    def addAnswerAtTime(self, record, now):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   676
        """Adds an answer if if does not expire by a certain time"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   677
        if record is not None:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   678
            if now == 0 or not record.isExpired(now):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   679
                self.answers.append((record, now))
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   680
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   681
    def addAuthoritativeAnswer(self, record):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   682
        """Adds an authoritative answer"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   683
        self.authorities.append(record)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   684
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   685
    def addAdditionalAnswer(self, record):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   686
        """Adds an additional answer"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   687
        self.additionals.append(record)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   688
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   689
    def writeByte(self, value):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   690
        """Writes a single byte to the packet"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   691
        format = '!c'
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   692
        self.data.append(struct.pack(format, chr(value)))
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   693
        self.size += 1
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   694
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   695
    def insertShort(self, index, value):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   696
        """Inserts an unsigned short in a certain position in the packet"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   697
        format = '!H'
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   698
        self.data.insert(index, struct.pack(format, value))
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   699
        self.size += 2
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
   700
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   701
    def writeShort(self, value):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   702
        """Writes an unsigned short to the packet"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   703
        format = '!H'
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   704
        self.data.append(struct.pack(format, value))
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   705
        self.size += 2
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   706
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   707
    def writeInt(self, value):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   708
        """Writes an unsigned integer to the packet"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   709
        format = '!I'
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   710
        self.data.append(struct.pack(format, int(value)))
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   711
        self.size += 4
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   712
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   713
    def writeString(self, value, length):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   714
        """Writes a string to the packet"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   715
        format = '!' + str(length) + 's'
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   716
        self.data.append(struct.pack(format, value))
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   717
        self.size += length
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   718
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   719
    def writeUTF(self, s):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   720
        """Writes a UTF-8 string of a given length to the packet"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   721
        utfstr = s.encode('utf-8')
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   722
        length = len(utfstr)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   723
        if length > 64:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   724
            raise NamePartTooLongException
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   725
        self.writeByte(length)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   726
        self.writeString(utfstr, length)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   727
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   728
    def writeName(self, name):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   729
        """Writes a domain name to the packet"""
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   730
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   731
        try:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   732
            # Find existing instance of this name in packet
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   733
            #
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   734
            index = self.names[name]
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   735
        except KeyError:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   736
            # No record of this name already, so write it
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   737
            # out as normal, recording the location of the name
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   738
            # for future pointers to it.
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   739
            #
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   740
            self.names[name] = self.size
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   741
            parts = name.split('.')
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   742
            if parts[-1] == '':
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   743
                parts = parts[:-1]
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   744
            for part in parts:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   745
                self.writeUTF(part)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   746
            self.writeByte(0)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   747
            return
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   748
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   749
        # An index was found, so write a pointer to it
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   750
        #
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   751
        self.writeByte((index >> 8) | 0xC0)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   752
        self.writeByte(index)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   753
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   754
    def writeQuestion(self, question):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   755
        """Writes a question to the packet"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   756
        self.writeName(question.name)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   757
        self.writeShort(question.type)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   758
        self.writeShort(question.clazz)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   759
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   760
    def writeRecord(self, record, now):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   761
        """Writes a record (answer, authoritative answer, additional) to
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   762
        the packet"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   763
        self.writeName(record.name)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   764
        self.writeShort(record.type)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   765
        if record.unique and self.multicast:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   766
            self.writeShort(record.clazz | _CLASS_UNIQUE)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   767
        else:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   768
            self.writeShort(record.clazz)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   769
        if now == 0:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   770
            self.writeInt(record.ttl)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   771
        else:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   772
            self.writeInt(record.getRemainingTTL(now))
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   773
        index = len(self.data)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   774
        # Adjust size for the short we will write before this record
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   775
        #
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   776
        self.size += 2
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   777
        record.write(self)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   778
        self.size -= 2
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
   779
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   780
        length = len(''.join(self.data[index:]))
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   781
        self.insertShort(index, length) # Here is the short we adjusted for
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   782
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   783
    def packet(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   784
        """Returns a string containing the packet's bytes
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   785
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   786
        No further parts should be added to the packet once this
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   787
        is done."""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   788
        if not self.finished:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   789
            self.finished = 1
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   790
            for question in self.questions:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   791
                self.writeQuestion(question)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   792
            for answer, time_ in self.answers:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   793
                self.writeRecord(answer, time_)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   794
            for authority in self.authorities:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   795
                self.writeRecord(authority, 0)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   796
            for additional in self.additionals:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   797
                self.writeRecord(additional, 0)
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
   798
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   799
            self.insertShort(0, len(self.additionals))
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   800
            self.insertShort(0, len(self.authorities))
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   801
            self.insertShort(0, len(self.answers))
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   802
            self.insertShort(0, len(self.questions))
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   803
            self.insertShort(0, self.flags)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   804
            if self.multicast:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   805
                self.insertShort(0, 0)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   806
            else:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   807
                self.insertShort(0, self.id)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   808
        return ''.join(self.data)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   809
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   810
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   811
class DNSCache(object):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   812
    """A cache of DNS entries"""
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
   813
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   814
    def __init__(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   815
        self.cache = {}
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   816
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   817
    def add(self, entry):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   818
        """Adds an entry"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   819
        try:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   820
            list = self.cache[entry.key]
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   821
        except KeyError:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   822
            list = self.cache[entry.key] = []
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   823
        list.append(entry)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   824
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   825
    def remove(self, entry):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   826
        """Removes an entry"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   827
        try:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   828
            list = self.cache[entry.key]
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   829
            list.remove(entry)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   830
        except KeyError:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   831
            pass
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   832
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   833
    def get(self, entry):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   834
        """Gets an entry by key.  Will return None if there is no
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   835
        matching entry."""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   836
        try:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   837
            list = self.cache[entry.key]
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   838
            return list[list.index(entry)]
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   839
        except (KeyError, ValueError):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   840
            return None
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   841
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   842
    def getByDetails(self, name, type, clazz):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   843
        """Gets an entry by details.  Will return None if there is
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   844
        no matching entry."""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   845
        entry = DNSEntry(name, type, clazz)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   846
        return self.get(entry)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   847
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   848
    def entriesWithName(self, name):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   849
        """Returns a list of entries whose key matches the name."""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   850
        try:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   851
            return self.cache[name]
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   852
        except KeyError:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   853
            return []
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   854
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   855
    def entries(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   856
        """Returns a list of all entries"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   857
        try:
28422
e2c6092ad422 zeroconf: replace reduce+add with itertools.chain
timeless <timeless@mozdev.org>
parents: 28421
diff changeset
   858
            return list(itertools.chain.from_iterable(self.cache.values()))
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   859
        except Exception:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   860
            return []
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   861
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   862
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   863
class Engine(threading.Thread):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   864
    """An engine wraps read access to sockets, allowing objects that
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   865
    need to receive data from sockets to be called back when the
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   866
    sockets are ready.
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   867
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   868
    A reader needs a handle_read() method, which is called when the socket
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   869
    it is interested in is ready for reading.
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   870
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   871
    Writers are not implemented here, because we only send short
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   872
    packets.
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   873
    """
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   874
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   875
    def __init__(self, zeroconf):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   876
        threading.Thread.__init__(self)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   877
        self.zeroconf = zeroconf
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   878
        self.readers = {} # maps socket to reader
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   879
        self.timeout = 5
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   880
        self.condition = threading.Condition()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   881
        self.start()
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   882
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   883
    def run(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   884
        while not globals()['_GLOBAL_DONE']:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   885
            rs = self.getReaders()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   886
            if len(rs) == 0:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   887
                # No sockets to manage, but we wait for the timeout
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   888
                # or addition of a socket
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   889
                #
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   890
                self.condition.acquire()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   891
                self.condition.wait(self.timeout)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   892
                self.condition.release()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   893
            else:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   894
                try:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   895
                    rr, wr, er = select.select(rs, [], [], self.timeout)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   896
                    for sock in rr:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   897
                        try:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   898
                            self.readers[sock].handle_read()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   899
                        except Exception:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   900
                            if not globals()['_GLOBAL_DONE']:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   901
                                traceback.print_exc()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   902
                except Exception:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   903
                    pass
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   904
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   905
    def getReaders(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   906
        self.condition.acquire()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   907
        result = self.readers.keys()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   908
        self.condition.release()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   909
        return result
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
   910
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   911
    def addReader(self, reader, socket):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   912
        self.condition.acquire()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   913
        self.readers[socket] = reader
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   914
        self.condition.notify()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   915
        self.condition.release()
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   916
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   917
    def delReader(self, socket):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   918
        self.condition.acquire()
28301
fd8a4d2d6541 zeroconf: del is not a function
timeless <timeless@mozdev.org>
parents: 28300
diff changeset
   919
        del self.readers[socket]
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   920
        self.condition.notify()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   921
        self.condition.release()
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   922
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   923
    def notify(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   924
        self.condition.acquire()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   925
        self.condition.notify()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   926
        self.condition.release()
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   927
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   928
class Listener(object):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   929
    """A Listener is used by this module to listen on the multicast
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   930
    group to which DNS messages are sent, allowing the implementation
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   931
    to cache information as it arrives.
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   932
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   933
    It requires registration with an Engine object in order to have
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   934
    the read() method called when a socket is available for reading."""
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
   935
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   936
    def __init__(self, zeroconf):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   937
        self.zeroconf = zeroconf
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   938
        self.zeroconf.engine.addReader(self, self.zeroconf.socket)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   939
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   940
    def handle_read(self):
34448
5385b76fd1fd zeroconf: do not crash if socket being read is closed by another thread
Jun Wu <quark@fb.com>
parents: 28504
diff changeset
   941
        data = addr = port = None
5385b76fd1fd zeroconf: do not crash if socket being read is closed by another thread
Jun Wu <quark@fb.com>
parents: 28504
diff changeset
   942
        sock = self.zeroconf.socket
5385b76fd1fd zeroconf: do not crash if socket being read is closed by another thread
Jun Wu <quark@fb.com>
parents: 28504
diff changeset
   943
        try:
5385b76fd1fd zeroconf: do not crash if socket being read is closed by another thread
Jun Wu <quark@fb.com>
parents: 28504
diff changeset
   944
            data, (addr, port) = sock.recvfrom(_MAX_MSG_ABSOLUTE)
5385b76fd1fd zeroconf: do not crash if socket being read is closed by another thread
Jun Wu <quark@fb.com>
parents: 28504
diff changeset
   945
        except socket.error as e:
5385b76fd1fd zeroconf: do not crash if socket being read is closed by another thread
Jun Wu <quark@fb.com>
parents: 28504
diff changeset
   946
            if e.errno == errno.EBADF:
5385b76fd1fd zeroconf: do not crash if socket being read is closed by another thread
Jun Wu <quark@fb.com>
parents: 28504
diff changeset
   947
                # some other thread may close the socket
5385b76fd1fd zeroconf: do not crash if socket being read is closed by another thread
Jun Wu <quark@fb.com>
parents: 28504
diff changeset
   948
                return
5385b76fd1fd zeroconf: do not crash if socket being read is closed by another thread
Jun Wu <quark@fb.com>
parents: 28504
diff changeset
   949
            else:
5385b76fd1fd zeroconf: do not crash if socket being read is closed by another thread
Jun Wu <quark@fb.com>
parents: 28504
diff changeset
   950
                raise
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   951
        self.data = data
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   952
        msg = DNSIncoming(data)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   953
        if msg.isQuery():
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   954
            # Always multicast responses
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   955
            #
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   956
            if port == _MDNS_PORT:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   957
                self.zeroconf.handleQuery(msg, _MDNS_ADDR, _MDNS_PORT)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   958
            # If it's not a multicast query, reply via unicast
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   959
            # and multicast
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   960
            #
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   961
            elif port == _DNS_PORT:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   962
                self.zeroconf.handleQuery(msg, addr, port)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   963
                self.zeroconf.handleQuery(msg, _MDNS_ADDR, _MDNS_PORT)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   964
        else:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   965
            self.zeroconf.handleResponse(msg)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   966
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   967
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   968
class Reaper(threading.Thread):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   969
    """A Reaper is used by this module to remove cache entries that
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   970
    have expired."""
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
   971
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   972
    def __init__(self, zeroconf):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   973
        threading.Thread.__init__(self)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   974
        self.zeroconf = zeroconf
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   975
        self.start()
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   976
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   977
    def run(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   978
        while True:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   979
            self.zeroconf.wait(10 * 1000)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   980
            if globals()['_GLOBAL_DONE']:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   981
                return
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   982
            now = currentTimeMillis()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   983
            for record in self.zeroconf.cache.entries():
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   984
                if record.isExpired(now):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   985
                    self.zeroconf.updateRecord(now, record)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   986
                    self.zeroconf.cache.remove(record)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   987
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   988
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   989
class ServiceBrowser(threading.Thread):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   990
    """Used to browse for a service of a specific type.
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   991
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   992
    The listener object will have its addService() and
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   993
    removeService() methods called when this browser
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   994
    discovers changes in the services availability."""
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
   995
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   996
    def __init__(self, zeroconf, type, listener):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   997
        """Creates a browser for a specific type"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   998
        threading.Thread.__init__(self)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
   999
        self.zeroconf = zeroconf
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1000
        self.type = type
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1001
        self.listener = listener
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1002
        self.services = {}
28419
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
  1003
        self.nexttime = currentTimeMillis()
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1004
        self.delay = _BROWSER_TIME
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1005
        self.list = []
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
  1006
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1007
        self.done = 0
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1008
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1009
        self.zeroconf.addListener(self, DNSQuestion(self.type, _TYPE_PTR,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1010
                                                    _CLASS_IN))
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1011
        self.start()
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1012
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1013
    def updateRecord(self, zeroconf, now, record):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1014
        """Callback invoked by Zeroconf when new information arrives.
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1015
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1016
        Updates information required by browser in the Zeroconf cache."""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1017
        if record.type == _TYPE_PTR and record.name == self.type:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1018
            expired = record.isExpired(now)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1019
            try:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1020
                oldrecord = self.services[record.alias.lower()]
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1021
                if not expired:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1022
                    oldrecord.resetTTL(record)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1023
                else:
28301
fd8a4d2d6541 zeroconf: del is not a function
timeless <timeless@mozdev.org>
parents: 28300
diff changeset
  1024
                    del self.services[record.alias.lower()]
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1025
                    callback = (lambda x:
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1026
                        self.listener.removeService(x, self.type, record.alias))
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1027
                    self.list.append(callback)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1028
                    return
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1029
            except Exception:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1030
                if not expired:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1031
                    self.services[record.alias.lower()] = record
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1032
                    callback = (lambda x:
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1033
                        self.listener.addService(x, self.type, record.alias))
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1034
                    self.list.append(callback)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1035
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1036
            expires = record.getExpirationTime(75)
28419
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
  1037
            if expires < self.nexttime:
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
  1038
                self.nexttime = expires
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1039
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1040
    def cancel(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1041
        self.done = 1
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1042
        self.zeroconf.notifyAll()
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1043
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1044
    def run(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1045
        while True:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1046
            event = None
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1047
            now = currentTimeMillis()
28419
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
  1048
            if len(self.list) == 0 and self.nexttime > now:
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
  1049
                self.zeroconf.wait(self.nexttime - now)
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1050
            if globals()['_GLOBAL_DONE'] or self.done:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1051
                return
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1052
            now = currentTimeMillis()
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1053
28419
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
  1054
            if self.nexttime <= now:
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1055
                out = DNSOutgoing(_FLAGS_QR_QUERY)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1056
                out.addQuestion(DNSQuestion(self.type, _TYPE_PTR, _CLASS_IN))
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1057
                for record in self.services.values():
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1058
                    if not record.isExpired(now):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1059
                        out.addAnswerAtTime(record, now)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1060
                self.zeroconf.send(out)
28419
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
  1061
                self.nexttime = now + self.delay
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1062
                self.delay = min(20 * 1000, self.delay * 2)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1063
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1064
            if len(self.list) > 0:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1065
                event = self.list.pop(0)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1066
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1067
            if event is not None:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1068
                event(self.zeroconf)
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
  1069
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1070
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1071
class ServiceInfo(object):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1072
    """Service information"""
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
  1073
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1074
    def __init__(self, type, name, address=None, port=None, weight=0,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1075
                 priority=0, properties=None, server=None):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1076
        """Create a service description.
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1077
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1078
        type: fully qualified service type name
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1079
        name: fully qualified service name
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1080
        address: IP address as unsigned short, network byte order
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1081
        port: port that the service runs on
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1082
        weight: weight of the service
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1083
        priority: priority of the service
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1084
        properties: dictionary of properties (or a string holding the bytes for
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1085
                    the text field)
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1086
        server: fully qualified name for service host (defaults to name)"""
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1087
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1088
        if not name.endswith(type):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1089
            raise BadTypeInNameException
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1090
        self.type = type
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1091
        self.name = name
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1092
        self.address = address
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1093
        self.port = port
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1094
        self.weight = weight
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1095
        self.priority = priority
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1096
        if server:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1097
            self.server = server
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1098
        else:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1099
            self.server = name
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1100
        self.setProperties(properties)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1101
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1102
    def setProperties(self, properties):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1103
        """Sets properties and text of this info from a dictionary"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1104
        if isinstance(properties, dict):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1105
            self.properties = properties
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1106
            list = []
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1107
            result = ''
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1108
            for key in properties:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1109
                value = properties[key]
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1110
                if value is None:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1111
                    suffix = ''
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1112
                elif isinstance(value, str):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1113
                    suffix = value
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1114
                elif isinstance(value, int):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1115
                    if value:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1116
                        suffix = 'true'
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1117
                    else:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1118
                        suffix = 'false'
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1119
                else:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1120
                    suffix = ''
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1121
                list.append('='.join((key, suffix)))
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1122
            for item in list:
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1123
                result = ''.join((result, struct.pack('!c', chr(len(item))),
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1124
                                  item))
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1125
            self.text = result
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1126
        else:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1127
            self.text = properties
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1128
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1129
    def setText(self, text):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1130
        """Sets properties and text given a text field"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1131
        self.text = text
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1132
        try:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1133
            result = {}
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1134
            end = len(text)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1135
            index = 0
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1136
            strs = []
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1137
            while index < end:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1138
                length = ord(text[index])
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1139
                index += 1
28300
15c5f50e7e13 zeroconf: add whitespace around operator
timeless <timeless@mozdev.org>
parents: 28299
diff changeset
  1140
                strs.append(text[index:index + length])
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1141
                index += length
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
  1142
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1143
            for s in strs:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1144
                eindex = s.find('=')
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1145
                if eindex == -1:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1146
                    # No equals sign at all
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1147
                    key = s
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1148
                    value = 0
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1149
                else:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1150
                    key = s[:eindex]
28300
15c5f50e7e13 zeroconf: add whitespace around operator
timeless <timeless@mozdev.org>
parents: 28299
diff changeset
  1151
                    value = s[eindex + 1:]
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1152
                    if value == 'true':
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1153
                        value = 1
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1154
                    elif value == 'false' or not value:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1155
                        value = 0
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1156
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1157
                # Only update non-existent properties
28420
d03b7800672c zeroconf: compare singleton using is
timeless <timeless@mozdev.org>
parents: 28419
diff changeset
  1158
                if key and result.get(key) is None:
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1159
                    result[key] = value
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1160
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1161
            self.properties = result
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1162
        except Exception:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1163
            traceback.print_exc()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1164
            self.properties = None
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
  1165
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1166
    def getType(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1167
        """Type accessor"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1168
        return self.type
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1169
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1170
    def getName(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1171
        """Name accessor"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1172
        if self.type is not None and self.name.endswith("." + self.type):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1173
            return self.name[:len(self.name) - len(self.type) - 1]
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1174
        return self.name
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1175
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1176
    def getAddress(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1177
        """Address accessor"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1178
        return self.address
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1179
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1180
    def getPort(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1181
        """Port accessor"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1182
        return self.port
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1183
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1184
    def getPriority(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1185
        """Priority accessor"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1186
        return self.priority
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1187
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1188
    def getWeight(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1189
        """Weight accessor"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1190
        return self.weight
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1191
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1192
    def getProperties(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1193
        """Properties accessor"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1194
        return self.properties
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1195
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1196
    def getText(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1197
        """Text accessor"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1198
        return self.text
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1199
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1200
    def getServer(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1201
        """Server accessor"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1202
        return self.server
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1203
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1204
    def updateRecord(self, zeroconf, now, record):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1205
        """Updates service information from a DNS record"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1206
        if record is not None and not record.isExpired(now):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1207
            if record.type == _TYPE_A:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1208
                #if record.name == self.name:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1209
                if record.name == self.server:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1210
                    self.address = record.address
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1211
            elif record.type == _TYPE_SRV:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1212
                if record.name == self.name:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1213
                    self.server = record.server
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1214
                    self.port = record.port
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1215
                    self.weight = record.weight
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1216
                    self.priority = record.priority
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1217
                    #self.address = None
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1218
                    self.updateRecord(zeroconf, now,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1219
                                      zeroconf.cache.getByDetails(self.server,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1220
                                      _TYPE_A, _CLASS_IN))
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1221
            elif record.type == _TYPE_TXT:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1222
                if record.name == self.name:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1223
                    self.setText(record.text)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1224
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1225
    def request(self, zeroconf, timeout):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1226
        """Returns true if the service could be discovered on the
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1227
        network, and updates this object with details discovered.
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1228
        """
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1229
        now = currentTimeMillis()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1230
        delay = _LISTENER_TIME
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1231
        next = now + delay
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1232
        last = now + timeout
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1233
        result = 0
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1234
        try:
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1235
            zeroconf.addListener(self, DNSQuestion(self.name, _TYPE_ANY,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1236
                                                   _CLASS_IN))
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1237
            while (self.server is None or self.address is None or
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1238
                   self.text is None):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1239
                if last <= now:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1240
                    return 0
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1241
                if next <= now:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1242
                    out = DNSOutgoing(_FLAGS_QR_QUERY)
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1243
                    out.addQuestion(DNSQuestion(self.name, _TYPE_SRV,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1244
                                                _CLASS_IN))
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1245
                    out.addAnswerAtTime(
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1246
                        zeroconf.cache.getByDetails(self.name,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1247
                                                    _TYPE_SRV,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1248
                                                    _CLASS_IN),
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1249
                                        now)
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1250
                    out.addQuestion(DNSQuestion(self.name, _TYPE_TXT,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1251
                                                _CLASS_IN))
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1252
                    out.addAnswerAtTime(
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1253
                        zeroconf.cache.getByDetails(self.name, _TYPE_TXT,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1254
                                                    _CLASS_IN),
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1255
                                        now)
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1256
                    if self.server is not None:
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1257
                        out.addQuestion(
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1258
                            DNSQuestion(self.server, _TYPE_A, _CLASS_IN))
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1259
                        out.addAnswerAtTime(
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1260
                            zeroconf.cache.getByDetails(self.server, _TYPE_A,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1261
                                                        _CLASS_IN),
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1262
                                            now)
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1263
                    zeroconf.send(out)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1264
                    next = now + delay
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1265
                    delay = delay * 2
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1266
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1267
                zeroconf.wait(min(next, last) - now)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1268
                now = currentTimeMillis()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1269
            result = 1
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1270
        finally:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1271
            zeroconf.removeListener(self)
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
  1272
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1273
        return result
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1274
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1275
    def __eq__(self, other):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1276
        """Tests equality of service name"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1277
        if isinstance(other, ServiceInfo):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1278
            return other.name == self.name
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1279
        return 0
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1280
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1281
    def __ne__(self, other):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1282
        """Non-equality test"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1283
        return not self.__eq__(other)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1284
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1285
    def __repr__(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1286
        """String representation"""
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1287
        result = ("service[%s,%s:%s," %
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1288
            (self.name, socket.inet_ntoa(self.getAddress()), self.port))
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1289
        if self.text is None:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1290
            result += "None"
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1291
        else:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1292
            if len(self.text) < 20:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1293
                result += self.text
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1294
            else:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1295
                result += self.text[:17] + "..."
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1296
        result += "]"
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1297
        return result
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
  1298
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1299
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1300
class Zeroconf(object):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1301
    """Implementation of Zeroconf Multicast DNS Service Discovery
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1302
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1303
    Supports registration, unregistration, queries and browsing.
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1304
    """
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1305
    def __init__(self, bindaddress=None):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1306
        """Creates an instance of the Zeroconf class, establishing
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1307
        multicast communications, listening and reaping threads."""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1308
        globals()['_GLOBAL_DONE'] = 0
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1309
        if bindaddress is None:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1310
            self.intf = socket.gethostbyname(socket.gethostname())
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1311
        else:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1312
            self.intf = bindaddress
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1313
        self.group = ('', _MDNS_PORT)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1314
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1315
        try:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1316
            self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1317
            self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1318
        except Exception:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1319
            # SO_REUSEADDR should be equivalent to SO_REUSEPORT for
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1320
            # multicast UDP sockets (p 731, "TCP/IP Illustrated,
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1321
            # Volume 2"), but some BSD-derived systems require
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1322
            # SO_REUSEPORT to be specified explicitly.  Also, not all
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1323
            # versions of Python have SO_REUSEPORT available.  So
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1324
            # if you're on a BSD-based system, and haven't upgraded
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1325
            # to Python 2.3 yet, you may find this library doesn't
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1326
            # work as expected.
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1327
            #
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1328
            pass
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1329
        self.socket.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_TTL, "\xff")
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1330
        self.socket.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, "\x01")
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1331
        try:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1332
            self.socket.bind(self.group)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1333
        except Exception:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1334
            # Some versions of linux raise an exception even though
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1335
            # SO_REUSEADDR and SO_REUSEPORT have been set, so ignore it
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1336
            pass
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1337
        self.socket.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1338
            socket.inet_aton(_MDNS_ADDR) + socket.inet_aton('0.0.0.0'))
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1339
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1340
        self.listeners = []
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1341
        self.browsers = []
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1342
        self.services = {}
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1343
        self.servicetypes = {}
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1344
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1345
        self.cache = DNSCache()
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1346
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1347
        self.condition = threading.Condition()
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
  1348
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1349
        self.engine = Engine(self)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1350
        self.listener = Listener(self)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1351
        self.reaper = Reaper(self)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1352
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1353
    def isLoopback(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1354
        return self.intf.startswith("127.0.0.1")
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1355
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1356
    def isLinklocal(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1357
        return self.intf.startswith("169.254.")
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1358
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1359
    def wait(self, timeout):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1360
        """Calling thread waits for a given number of milliseconds or
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1361
        until notified."""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1362
        self.condition.acquire()
28300
15c5f50e7e13 zeroconf: add whitespace around operator
timeless <timeless@mozdev.org>
parents: 28299
diff changeset
  1363
        self.condition.wait(timeout / 1000)
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1364
        self.condition.release()
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1365
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1366
    def notifyAll(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1367
        """Notifies all waiting threads"""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1368
        self.condition.acquire()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1369
        self.condition.notifyAll()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1370
        self.condition.release()
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1371
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1372
    def getServiceInfo(self, type, name, timeout=3000):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1373
        """Returns network's service information for a particular
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1374
        name and type, or None if no service matches by the timeout,
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1375
        which defaults to 3 seconds."""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1376
        info = ServiceInfo(type, name)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1377
        if info.request(self, timeout):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1378
            return info
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1379
        return None
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1380
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1381
    def addServiceListener(self, type, listener):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1382
        """Adds a listener for a particular service type.  This object
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1383
        will then have its updateRecord method called when information
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1384
        arrives for that type."""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1385
        self.removeServiceListener(listener)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1386
        self.browsers.append(ServiceBrowser(self, type, listener))
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1387
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1388
    def removeServiceListener(self, listener):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1389
        """Removes a listener from the set that is currently listening."""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1390
        for browser in self.browsers:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1391
            if browser.listener == listener:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1392
                browser.cancel()
28301
fd8a4d2d6541 zeroconf: del is not a function
timeless <timeless@mozdev.org>
parents: 28300
diff changeset
  1393
                del browser
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1394
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1395
    def registerService(self, info, ttl=_DNS_TTL):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1396
        """Registers service information to the network with a default TTL
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1397
        of 60 seconds.  Zeroconf will then respond to requests for
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1398
        information for that service.  The name of the service may be
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1399
        changed if needed to make it unique on the network."""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1400
        self.checkService(info)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1401
        self.services[info.name.lower()] = info
28421
6d72cc613fc4 zeroconf: replace has_key with in
timeless <timeless@mozdev.org>
parents: 28420
diff changeset
  1402
        if info.type in self.servicetypes:
28300
15c5f50e7e13 zeroconf: add whitespace around operator
timeless <timeless@mozdev.org>
parents: 28299
diff changeset
  1403
            self.servicetypes[info.type] += 1
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1404
        else:
28300
15c5f50e7e13 zeroconf: add whitespace around operator
timeless <timeless@mozdev.org>
parents: 28299
diff changeset
  1405
            self.servicetypes[info.type] = 1
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1406
        now = currentTimeMillis()
28419
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
  1407
        nexttime = now
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1408
        i = 0
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1409
        while i < 3:
28419
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
  1410
            if now < nexttime:
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
  1411
                self.wait(nexttime - now)
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1412
                now = currentTimeMillis()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1413
                continue
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1414
            out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA)
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1415
            out.addAnswerAtTime(DNSPointer(info.type, _TYPE_PTR,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1416
                _CLASS_IN, ttl, info.name), 0)
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1417
            out.addAnswerAtTime(
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1418
                DNSService(
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1419
                    info.name, _TYPE_SRV,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1420
                    _CLASS_IN, ttl, info.priority, info.weight, info.port,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1421
                    info.server),
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1422
                0)
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1423
            out.addAnswerAtTime(
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1424
                DNSText(info.name, _TYPE_TXT, _CLASS_IN, ttl, info.text),
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1425
                0)
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1426
            if info.address:
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1427
                out.addAnswerAtTime(DNSAddress(info.server, _TYPE_A,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1428
                    _CLASS_IN, ttl, info.address), 0)
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1429
            self.send(out)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1430
            i += 1
28419
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
  1431
            nexttime += _REGISTER_TIME
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1432
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1433
    def unregisterService(self, info):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1434
        """Unregister a service."""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1435
        try:
28301
fd8a4d2d6541 zeroconf: del is not a function
timeless <timeless@mozdev.org>
parents: 28300
diff changeset
  1436
            del self.services[info.name.lower()]
28300
15c5f50e7e13 zeroconf: add whitespace around operator
timeless <timeless@mozdev.org>
parents: 28299
diff changeset
  1437
            if self.servicetypes[info.type] > 1:
15c5f50e7e13 zeroconf: add whitespace around operator
timeless <timeless@mozdev.org>
parents: 28299
diff changeset
  1438
                self.servicetypes[info.type] -= 1
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1439
            else:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1440
                del self.servicetypes[info.type]
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1441
        except KeyError:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1442
            pass
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1443
        now = currentTimeMillis()
28419
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
  1444
        nexttime = now
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1445
        i = 0
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1446
        while i < 3:
28419
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
  1447
            if now < nexttime:
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
  1448
                self.wait(nexttime - now)
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1449
                now = currentTimeMillis()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1450
                continue
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1451
            out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA)
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1452
            out.addAnswerAtTime(
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1453
                DNSPointer(info.type, _TYPE_PTR, _CLASS_IN, 0, info.name), 0)
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1454
            out.addAnswerAtTime(
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1455
                DNSService(info.name, _TYPE_SRV,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1456
                           _CLASS_IN, 0, info.priority, info.weight, info.port,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1457
                           info.name),
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1458
                0)
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1459
            out.addAnswerAtTime(DNSText(info.name, _TYPE_TXT,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1460
                _CLASS_IN, 0, info.text), 0)
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1461
            if info.address:
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1462
                out.addAnswerAtTime(DNSAddress(info.server, _TYPE_A,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1463
                    _CLASS_IN, 0, info.address), 0)
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1464
            self.send(out)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1465
            i += 1
28419
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
  1466
            nexttime += _UNREGISTER_TIME
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1467
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1468
    def unregisterAllServices(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1469
        """Unregister all registered services."""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1470
        if len(self.services) > 0:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1471
            now = currentTimeMillis()
28419
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
  1472
            nexttime = now
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1473
            i = 0
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1474
            while i < 3:
28419
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
  1475
                if now < nexttime:
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
  1476
                    self.wait(nexttime - now)
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1477
                    now = currentTimeMillis()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1478
                    continue
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1479
                out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1480
                for info in self.services.values():
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1481
                    out.addAnswerAtTime(DNSPointer(info.type, _TYPE_PTR,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1482
                        _CLASS_IN, 0, info.name), 0)
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1483
                    out.addAnswerAtTime(
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1484
                        DNSService(info.name, _TYPE_SRV,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1485
                                   _CLASS_IN, 0, info.priority, info.weight,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1486
                                   info.port, info.server),
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1487
                        0)
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1488
                    out.addAnswerAtTime(DNSText(info.name, _TYPE_TXT,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1489
                        _CLASS_IN, 0, info.text), 0)
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1490
                    if info.address:
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1491
                        out.addAnswerAtTime(DNSAddress(info.server, _TYPE_A,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1492
                           _CLASS_IN, 0, info.address), 0)
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1493
                self.send(out)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1494
                i += 1
28419
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
  1495
                nexttime += _UNREGISTER_TIME
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1496
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1497
    def checkService(self, info):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1498
        """Checks the network for a unique service name, modifying the
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1499
        ServiceInfo passed in if it is not unique."""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1500
        now = currentTimeMillis()
28419
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
  1501
        nexttime = now
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1502
        i = 0
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1503
        while i < 3:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1504
            for record in self.cache.entriesWithName(info.type):
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1505
                if (record.type == _TYPE_PTR and not record.isExpired(now) and
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1506
                    record.alias == info.name):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1507
                    if (info.name.find('.') < 0):
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1508
                        info.name = ("%w.[%s:%d].%s" %
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1509
                            (info.name, info.address, info.port, info.type))
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1510
                        self.checkService(info)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1511
                        return
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1512
                    raise NonUniqueNameException
28419
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
  1513
            if now < nexttime:
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
  1514
                self.wait(nexttime - now)
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1515
                now = currentTimeMillis()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1516
                continue
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1517
            out = DNSOutgoing(_FLAGS_QR_QUERY | _FLAGS_AA)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1518
            self.debug = out
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1519
            out.addQuestion(DNSQuestion(info.type, _TYPE_PTR, _CLASS_IN))
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1520
            out.addAuthoritativeAnswer(DNSPointer(info.type, _TYPE_PTR,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1521
                _CLASS_IN, _DNS_TTL, info.name))
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1522
            self.send(out)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1523
            i += 1
28419
eb9d0e828c30 zeroconf: remove camelcase in identifiers
timeless <timeless@mozdev.org>
parents: 28302
diff changeset
  1524
            nexttime += _CHECK_TIME
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1525
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1526
    def addListener(self, listener, question):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1527
        """Adds a listener for a given question.  The listener will have
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1528
        its updateRecord method called when information is available to
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1529
        answer the question."""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1530
        now = currentTimeMillis()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1531
        self.listeners.append(listener)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1532
        if question is not None:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1533
            for record in self.cache.entriesWithName(question.name):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1534
                if question.answeredBy(record) and not record.isExpired(now):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1535
                    listener.updateRecord(self, now, record)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1536
        self.notifyAll()
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1537
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1538
    def removeListener(self, listener):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1539
        """Removes a listener."""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1540
        try:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1541
            self.listeners.remove(listener)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1542
            self.notifyAll()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1543
        except Exception:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1544
            pass
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1545
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1546
    def updateRecord(self, now, rec):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1547
        """Used to notify listeners of new information that has updated
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1548
        a record."""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1549
        for listener in self.listeners:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1550
            listener.updateRecord(self, now, rec)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1551
        self.notifyAll()
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1552
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1553
    def handleResponse(self, msg):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1554
        """Deal with incoming response packets.  All answers
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1555
        are held in the cache, and listeners are notified."""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1556
        now = currentTimeMillis()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1557
        for record in msg.answers:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1558
            expired = record.isExpired(now)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1559
            if record in self.cache.entries():
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1560
                if expired:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1561
                    self.cache.remove(record)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1562
                else:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1563
                    entry = self.cache.get(record)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1564
                    if entry is not None:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1565
                        entry.resetTTL(record)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1566
                        record = entry
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1567
            else:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1568
                self.cache.add(record)
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
  1569
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1570
            self.updateRecord(now, record)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1571
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1572
    def handleQuery(self, msg, addr, port):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1573
        """Deal with incoming query packets.  Provides a response if
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1574
        possible."""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1575
        out = None
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1576
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1577
        # Support unicast client responses
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1578
        #
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1579
        if port != _MDNS_PORT:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1580
            out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA, 0)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1581
            for question in msg.questions:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1582
                out.addQuestion(question)
7874
d812029cda85 cleanup: drop variables for unused return values
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7071
diff changeset
  1583
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1584
        for question in msg.questions:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1585
            if question.type == _TYPE_PTR:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1586
                if question.name == "_services._dns-sd._udp.local.":
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1587
                    for stype in self.servicetypes.keys():
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1588
                        if out is None:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1589
                            out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA)
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1590
                        out.addAnswer(msg,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1591
                                      DNSPointer(
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1592
                                          "_services._dns-sd._udp.local.",
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1593
                                           _TYPE_PTR, _CLASS_IN,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1594
                                           _DNS_TTL, stype))
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1595
                for service in self.services.values():
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1596
                    if question.name == service.type:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1597
                        if out is None:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1598
                            out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA)
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1599
                        out.addAnswer(msg, DNSPointer(service.type, _TYPE_PTR,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1600
                            _CLASS_IN, _DNS_TTL, service.name))
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1601
            else:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1602
                try:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1603
                    if out is None:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1604
                        out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA)
7874
d812029cda85 cleanup: drop variables for unused return values
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7071
diff changeset
  1605
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1606
                    # Answer A record queries for any service addresses we know
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1607
                    if question.type == _TYPE_A or question.type == _TYPE_ANY:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1608
                        for service in self.services.values():
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1609
                            if service.server == question.name.lower():
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1610
                                out.addAnswer(msg,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1611
                                    DNSAddress(question.name, _TYPE_A,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1612
                                               _CLASS_IN | _CLASS_UNIQUE,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1613
                                               _DNS_TTL, service.address))
7874
d812029cda85 cleanup: drop variables for unused return values
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7071
diff changeset
  1614
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1615
                    service = self.services.get(question.name.lower(), None)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1616
                    if not service: continue
7874
d812029cda85 cleanup: drop variables for unused return values
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7071
diff changeset
  1617
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1618
                    if (question.type == _TYPE_SRV or
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1619
                        question.type == _TYPE_ANY):
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1620
                        out.addAnswer(msg,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1621
                            DNSService(question.name, _TYPE_SRV,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1622
                                       _CLASS_IN | _CLASS_UNIQUE,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1623
                                       _DNS_TTL, service.priority,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1624
                                       service.weight, service.port,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1625
                                       service.server))
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1626
                    if (question.type == _TYPE_TXT or
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1627
                        question.type == _TYPE_ANY):
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1628
                        out.addAnswer(msg, DNSText(question.name, _TYPE_TXT,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1629
                            _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.text))
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1630
                    if question.type == _TYPE_SRV:
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1631
                        out.addAdditionalAnswer(
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1632
                            DNSAddress(service.server, _TYPE_A,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1633
                                       _CLASS_IN | _CLASS_UNIQUE,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1634
                                       _DNS_TTL, service.address))
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1635
                except Exception:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1636
                    traceback.print_exc()
7874
d812029cda85 cleanup: drop variables for unused return values
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7071
diff changeset
  1637
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1638
        if out is not None and out.answers:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1639
            out.id = msg.id
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1640
            self.send(out, addr, port)
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1641
28302
e96a3ae025ed zeroconf: remove whitespace around = for named parameters
timeless <timeless@mozdev.org>
parents: 28301
diff changeset
  1642
    def send(self, out, addr=_MDNS_ADDR, port=_MDNS_PORT):
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1643
        """Sends an outgoing packet."""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1644
        # This is a quick test to see if we can parse the packets we generate
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1645
        #temp = DNSIncoming(out.packet())
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1646
        try:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1647
            self.socket.sendto(out.packet(), 0, (addr, port))
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1648
        except Exception:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1649
            # Ignore this, it may be a temporary loss of network connection
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1650
            pass
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1651
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1652
    def close(self):
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1653
        """Ends the background threads, and prevent this instance from
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1654
        servicing further queries."""
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1655
        if globals()['_GLOBAL_DONE'] == 0:
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1656
            globals()['_GLOBAL_DONE'] = 1
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1657
            self.notifyAll()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1658
            self.engine.notify()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1659
            self.unregisterAllServices()
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1660
            self.socket.setsockopt(socket.SOL_IP, socket.IP_DROP_MEMBERSHIP,
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1661
                socket.inet_aton(_MDNS_ADDR) + socket.inet_aton('0.0.0.0'))
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1662
            self.socket.close()
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
  1663
7071
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1664
# Test a few module features, including service registration, service
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1665
# query (for Zoe), and service unregistration.
643c751e60b2 zeroconf: initial implementation
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
  1666
7877
eba7f12b0c51 cleanup: whitespace cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7874
diff changeset
  1667
if __name__ == '__main__':
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1668
    print("Multicast DNS Service Discovery for Python, version", __version__)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1669
    r = Zeroconf()
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1670
    print("1. Testing registration of a service...")
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1671
    desc = {'version':'0.10','a':'test value', 'b':'another value'}
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1672
    info = ServiceInfo("_http._tcp.local.",
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1673
                       "My Service Name._http._tcp.local.",
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1674
        socket.inet_aton("127.0.0.1"), 1234, 0, 0, desc)
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1675
    print("   Registering service...")
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1676
    r.registerService(info)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1677
    print("   Registration done.")
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1678
    print("2. Testing query of service information...")
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1679
    print("   Getting ZOE service:",
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1680
        str(r.getServiceInfo("_http._tcp.local.", "ZOE._http._tcp.local.")))
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1681
    print("   Query done.")
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1682
    print("3. Testing query of own service...")
28299
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1683
    print("   Getting self:",
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1684
        str(r.getServiceInfo("_http._tcp.local.",
acea9dd8cf7e zeroconf: wrap long lines
timeless <timeless@mozdev.org>
parents: 28298
diff changeset
  1685
                             "My Service Name._http._tcp.local.")))
28298
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1686
    print("   Query done.")
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1687
    print("4. Testing unregister of service information...")
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1688
    r.unregisterService(info)
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1689
    print("   Unregister done.")
c318e8fd0e62 zeroconf: drop tabs
timeless <timeless@mozdev.org>
parents: 28297
diff changeset
  1690
    r.close()