Mono.Zeroconf – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 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 }
62  
63 public void Resolve()
64 {
65 Resolve(false);
66 }
67  
68 public void Resolve(bool requery)
69 {
70 if(resolve_pending) {
71 return;
72 }
73  
74 is_resolved = false;
75 resolve_pending = true;
76  
77 if(requery) {
78 InterfaceIndex = 0;
79 }
80  
81 ServiceRef sd_ref;
82 ServiceError error = Native.DNSServiceResolve(out sd_ref, ServiceFlags.None,
83 InterfaceIndex, Name, RegType, ReplyDomain, resolve_reply_handler, IntPtr.Zero);
84  
85 if(error != ServiceError.NoError) {
86 throw new ServiceErrorException(error);
87 }
88  
89 sd_ref.Process();
90 }
91  
92 public void RefreshTxtRecord()
93 {
94 // Should probably make this async?
95  
96 ServiceRef sd_ref;
97 ServiceError error = Native.DNSServiceQueryRecord(out sd_ref, ServiceFlags.None, 0,
98 fullname, ServiceType.TXT, ServiceClass.IN, query_record_reply_handler, IntPtr.Zero);
99  
100 if(error != ServiceError.NoError) {
101 throw new ServiceErrorException(error);
102 }
103  
104 sd_ref.Process();
105 }
106  
107 private void OnResolveReply(ServiceRef sdRef, ServiceFlags flags, uint interfaceIndex,
108 ServiceError errorCode, string fullname, string hosttarget, ushort port, ushort txtLen,
109 IntPtr txtRecord, IntPtr contex)
110 {
111 is_resolved = true;
112 resolve_pending = false;
113  
114 InterfaceIndex = interfaceIndex;
115 FullName = fullname;
116 this.port = port;
117 TxtRecord = new TxtRecord(txtLen, txtRecord);
118  
119 sdRef.Deallocate();
120  
121 // Run an A query to resolve the IP address
122 ServiceRef sd_ref;
123  
124 if (AddressProtocol == AddressProtocol.Any || AddressProtocol == AddressProtocol.IPv4) {
125 ServiceError error = Native.DNSServiceQueryRecord(out sd_ref, ServiceFlags.None, interfaceIndex,
126 hosttarget, ServiceType.A, ServiceClass.IN, query_record_reply_handler, IntPtr.Zero);
127  
128 if(error != ServiceError.NoError) {
129 throw new ServiceErrorException(error);
130 }
131  
132 sd_ref.Process();
133 }
134  
135 if (AddressProtocol == AddressProtocol.Any || AddressProtocol == AddressProtocol.IPv6) {
136 ServiceError error = Native.DNSServiceQueryRecord(out sd_ref, ServiceFlags.None, interfaceIndex,
137 hosttarget, ServiceType.AAAA, ServiceClass.IN, query_record_reply_handler, IntPtr.Zero);
138  
139 if(error != ServiceError.NoError) {
140 throw new ServiceErrorException(error);
141 }
142  
143 sd_ref.Process();
144 }
145 }
146  
147 private void OnQueryRecordReply(ServiceRef sdRef, ServiceFlags flags, uint interfaceIndex,
148 ServiceError errorCode, string fullname, ServiceType rrtype, ServiceClass rrclass, ushort rdlen,
149 IntPtr rdata, uint ttl, IntPtr context)
150 {
151 switch(rrtype) {
152 case ServiceType.A:
153 IPAddress address;
154  
155 if(rdlen == 4) {
156 // ~4.5 times faster than Marshal.Copy into byte[4]
157 uint address_raw = (uint)(Marshal.ReadByte (rdata, 3) << 24);
158 address_raw |= (uint)(Marshal.ReadByte (rdata, 2) << 16);
159 address_raw |= (uint)(Marshal.ReadByte (rdata, 1) << 8);
160 address_raw |= (uint)Marshal.ReadByte (rdata, 0);
161  
162 address = new IPAddress(address_raw);
163 } else if(rdlen == 16) {
164 byte [] address_raw = new byte[rdlen];
165 Marshal.Copy(rdata, address_raw, 0, rdlen);
166 address = new IPAddress(address_raw, interfaceIndex);
167 } else {
168 break;
169 }
170  
171 if(hostentry == null) {
172 hostentry = new IPHostEntry();
173 hostentry.HostName = hosttarget;
174 }
175  
176 if(hostentry.AddressList != null) {
177 ArrayList list = new ArrayList(hostentry.AddressList);
178 list.Add(address);
179 hostentry.AddressList = list.ToArray(typeof(IPAddress)) as IPAddress [];
180 } else {
181 hostentry.AddressList = new IPAddress [] { address };
182 }
183  
184 ServiceResolvedEventHandler handler = Resolved;
185 if(handler != null) {
186 handler(this, new ServiceResolvedEventArgs(this));
187 }
188  
189 break;
190 case ServiceType.TXT:
191 if(TxtRecord != null) {
192 TxtRecord.Dispose();
193 }
194  
195 TxtRecord = new TxtRecord(rdlen, rdata);
196 break;
197 default:
198 break;
199 }
200  
201 sdRef.Deallocate();
202 }
203  
204 public bool IsResolved {
205 get { return is_resolved; }
206 }
207 }
208 }
209