Mono.Zeroconf – Blame information for rev 2

Subversion Repositories:
Rev:
Rev Author Line No. Line
2 office 1 //
2 // BrowseService.cs
3 //
4 // Authors:
5 // Aaron Bockover <abockover@novell.com>
6 //
7 // Copyright (C) 2006-2008 Novell, Inc (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28  
29 using System;
30 using System.Net;
31 using System.Text;
32 using System.Collections;
33 using System.Runtime.InteropServices;
34  
35 namespace Mono.Zeroconf.Providers.Bonjour
36 {
37 public sealed class BrowseService : Service, IResolvableService
38 {
39 private bool is_resolved = false;
40 private bool resolve_pending = false;
41  
42 private Native.DNSServiceResolveReply resolve_reply_handler;
43 private Native.DNSServiceQueryRecordReply query_record_reply_handler;
44  
45 public event ServiceResolvedEventHandler Resolved;
46  
47 public BrowseService()
48 {
49 SetupCallbacks();
50 }
51  
52 public BrowseService(string name, string replyDomain, string regtype) : base(name, replyDomain, regtype)
53 {
54 SetupCallbacks();
55 }
56  
57 private void SetupCallbacks()
58 {
59 resolve_reply_handler = new Native.DNSServiceResolveReply(OnResolveReply);
60 query_record_reply_handler = new Native.DNSServiceQueryRecordReply(OnQueryRecordReply);
61 resolveAction = new Action<bool>(Resolve);
62 }
63  
64 private Action<bool> resolveAction;
65  
66 public void Resolve()
67 {
68 Resolve(false);
69 // If people call this in a ServiceAdded eventhandler (which they genreally do)
70 // We need to invoke onto another thread otherwise we block processing any more results.
71  
72 resolveAction.BeginInvoke(false, null, null);
73 }
74  
75 public void Resolve(bool requery)
76 {
77 if(resolve_pending) {
78 return;
79 }
80  
81 is_resolved = false;
82 resolve_pending = true;
83  
84 if(requery) {
85 InterfaceIndex = 0;
86 }
87  
88 ServiceRef sd_ref;
89 ServiceError error = Native.DNSServiceResolve(out sd_ref, ServiceFlags.None,
90 InterfaceIndex, Encoding.UTF8.GetBytes(Name), RegType, ReplyDomain, resolve_reply_handler, IntPtr.Zero);
91  
92 if(error != ServiceError.NoError) {
93 throw new ServiceErrorException(error);
94 }
95  
96 sd_ref.Process();
97 }
98  
99 public void RefreshTxtRecord()
100 {
101 // Should probably make this async?
102  
103 ServiceRef sd_ref;
104 ServiceError error = Native.DNSServiceQueryRecord(out sd_ref, ServiceFlags.None, 0,
105 fullname, ServiceType.TXT, ServiceClass.IN, query_record_reply_handler, IntPtr.Zero);
106  
107 if(error != ServiceError.NoError) {
108 throw new ServiceErrorException(error);
109 }
110  
111 sd_ref.Process();
112 }
113  
114 private void OnResolveReply(ServiceRef sdRef, ServiceFlags flags, uint interfaceIndex,
115 ServiceError errorCode, IntPtr fullname, string hosttarget, ushort port, ushort txtLen,
116 IntPtr txtRecord, IntPtr contex)
117 {
118 is_resolved = true;
119 resolve_pending = false;
120  
121 InterfaceIndex = interfaceIndex;
122 FullName = Native.Utf8toString(fullname);
123 this.port = (ushort)IPAddress.NetworkToHostOrder((short)port);
124 TxtRecord = new TxtRecord(txtLen, txtRecord);
125 this.hosttarget = hosttarget;
126  
127 sdRef.Deallocate();
128  
129 // Run an A query to resolve the IP address
130 ServiceRef sd_ref;
131  
132 if (AddressProtocol == AddressProtocol.Any || AddressProtocol == AddressProtocol.IPv4) {
133 ServiceError error = Native.DNSServiceQueryRecord(out sd_ref, ServiceFlags.None, interfaceIndex,
134 hosttarget, ServiceType.A, ServiceClass.IN, query_record_reply_handler, IntPtr.Zero);
135  
136 if(error != ServiceError.NoError) {
137 throw new ServiceErrorException(error);
138 }
139  
140 sd_ref.Process();
141 }
142  
143 if (AddressProtocol == AddressProtocol.Any || AddressProtocol == AddressProtocol.IPv6) {
144 ServiceError error = Native.DNSServiceQueryRecord(out sd_ref, ServiceFlags.None, interfaceIndex,
145 hosttarget, ServiceType.AAAA, ServiceClass.IN, query_record_reply_handler, IntPtr.Zero);
146  
147 if(error != ServiceError.NoError) {
148 throw new ServiceErrorException(error);
149 }
150  
151 sd_ref.Process();
152 }
153  
154 if (hostentry.AddressList != null)
155 {
156 ServiceResolvedEventHandler handler = Resolved;
157 if (handler != null)
158 {
159 handler(this, new ServiceResolvedEventArgs(this));
160 }
161 }
162 }
163  
164 private void OnQueryRecordReply(ServiceRef sdRef, ServiceFlags flags, uint interfaceIndex,
165 ServiceError errorCode, string fullname, ServiceType rrtype, ServiceClass rrclass, ushort rdlen,
166 IntPtr rdata, uint ttl, IntPtr context)
167 {
168 switch(rrtype) {
169 case ServiceType.A:
170 case ServiceType.AAAA:
171 IPAddress address;
172  
173 if(rdlen == 4) {
174 // ~4.5 times faster than Marshal.Copy into byte[4]
175 uint address_raw = (uint)(Marshal.ReadByte (rdata, 3) << 24);
176 address_raw |= (uint)(Marshal.ReadByte (rdata, 2) << 16);
177 address_raw |= (uint)(Marshal.ReadByte (rdata, 1) << 8);
178 address_raw |= (uint)Marshal.ReadByte (rdata, 0);
179  
180 address = new IPAddress(address_raw);
181 } else if(rdlen == 16) {
182 byte [] address_raw = new byte[rdlen];
183 Marshal.Copy(rdata, address_raw, 0, rdlen);
184 address = new IPAddress(address_raw, interfaceIndex);
185 } else {
186 break;
187 }
188  
189 if(hostentry == null) {
190 hostentry = new IPHostEntry();
191 hostentry.HostName = hosttarget;
192 }
193  
194 if(hostentry.AddressList != null) {
195 ArrayList list = new ArrayList(hostentry.AddressList);
196 list.Add(address);
197 hostentry.AddressList = list.ToArray(typeof(IPAddress)) as IPAddress [];
198 } else {
199 hostentry.AddressList = new IPAddress [] { address };
200 }
201  
202 ServiceResolvedEventHandler handler = Resolved;
203 if(handler != null) {
204 handler(this, new ServiceResolvedEventArgs(this));
205 }
206  
207 break;
208 case ServiceType.TXT:
209 if(TxtRecord != null) {
210 TxtRecord.Dispose();
211 }
212  
213 TxtRecord = new TxtRecord(rdlen, rdata);
214 break;
215 default:
216 break;
217 }
218  
219  
220 if ((flags & ServiceFlags.MoreComing) != ServiceFlags.MoreComing)
221 {
222 sdRef.Deallocate();
223 }
224 }
225  
226 public bool IsResolved {
227 get { return is_resolved; }
228 }
229 }
230 }
231