annotate hgext/zeroconf/Zeroconf.py @ 21740:2b3b60031b6f

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