Mono.Zeroconf – Blame information for rev 2

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 //
2 // ServiceBrowser.cs
3 //
4 // Authors:
5 // Aaron Bockover <abockover@novell.com>
6 //
7 // Copyright (C) 2006-2007 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.Collections;
31 using System.Collections.Generic;
32 using System.Threading;
33  
34 namespace Mono.Zeroconf.Providers.Bonjour
35 {
36 public class ServiceBrowseEventArgs : Mono.Zeroconf.ServiceBrowseEventArgs
37 {
38 private bool more_coming;
39  
40 public ServiceBrowseEventArgs(BrowseService service, bool moreComing) : base(service)
41 {
42 this.more_coming = moreComing;
43 }
44  
45 public bool MoreComing {
46 get { return more_coming; }
47 }
48 }
49  
50 public class ServiceBrowser : IServiceBrowser, IDisposable
51 {
52 private uint interface_index;
53 private AddressProtocol address_protocol;
54 private string regtype;
55 private string domain;
56  
57 private ServiceRef sd_ref = ServiceRef.Zero;
58 private Dictionary<string, IResolvableService> service_table = new Dictionary<string, IResolvableService> ();
59  
60 private Native.DNSServiceBrowseReply browse_reply_handler;
61  
62 private Thread thread;
63  
64 public event ServiceBrowseEventHandler ServiceAdded;
65 public event ServiceBrowseEventHandler ServiceRemoved;
66  
67 public ServiceBrowser()
68 {
69 browse_reply_handler = new Native.DNSServiceBrowseReply(OnBrowseReply);
70 }
71  
72 public void Browse (uint interfaceIndex, AddressProtocol addressProtocol, string regtype, string domain)
73 {
74 Configure(interfaceIndex, addressProtocol, regtype, domain);
75 StartAsync();
76 }
77  
78 public void Configure(uint interfaceIndex, AddressProtocol addressProtocol, string regtype, string domain)
79 {
80 this.interface_index = interfaceIndex;
81 this.address_protocol = addressProtocol;
82 this.regtype = regtype;
83 this.domain = domain;
84  
85 if(regtype == null) {
86 throw new ArgumentNullException("regtype");
87 }
88 }
89  
90 private void Start(bool @async)
91 {
92 if(thread != null) {
93 throw new InvalidOperationException("ServiceBrowser is already started");
94 }
95  
96 if(@async) {
97 thread = new Thread(new ThreadStart(ThreadedStart));
98 thread.IsBackground = true;
99 thread.Start();
100 } else {
101 ProcessStart();
102 }
103 }
104  
105 public void Start()
106 {
107 Start(false);
108 }
109  
110 public void StartAsync()
111 {
112 Start(true);
113 }
114  
115 private void ThreadedStart()
116 {
117 try {
118 ProcessStart();
119 } catch(ThreadAbortException) {
120 Thread.ResetAbort();
121 }
122  
123 thread = null;
124 }
125  
126 private void ProcessStart()
127 {
128 ServiceError error = Native.DNSServiceBrowse(out sd_ref, ServiceFlags.Default,
129 interface_index, regtype, domain, browse_reply_handler, IntPtr.Zero);
130  
131 if(error != ServiceError.NoError) {
132 throw new ServiceErrorException(error);
133 }
134  
135 sd_ref.Process();
136 }
137  
138 public void Stop()
139 {
140 if(sd_ref != ServiceRef.Zero) {
141 sd_ref.Deallocate();
142 sd_ref = ServiceRef.Zero;
143 }
144  
145 if(thread != null) {
146 thread.Abort();
147 thread = null;
148 }
149 }
150  
151 public void Dispose()
152 {
153 Stop();
154 }
155  
156 public IEnumerator<IResolvableService> GetEnumerator ()
157 {
158 lock (this) {
159 foreach (IResolvableService service in service_table.Values) {
160 yield return service;
161 }
162 }
163 }
164  
165 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
166 {
167 return GetEnumerator ();
168 }
169  
2 office 170 private void OnBrowseReply(ServiceRef sdRef, ServiceFlags flags, uint interfaceIndex, ServiceError errorCode,
171 IntPtr serviceName, string regtype, string replyDomain, IntPtr context)
1 office 172 {
2 office 173 string name = Native.Utf8toString(serviceName);
1 office 174 BrowseService service = new BrowseService();
175 service.Flags = flags;
2 office 176 service.Name = name;
1 office 177 service.RegType = regtype;
178 service.ReplyDomain = replyDomain;
179 service.InterfaceIndex = interfaceIndex;
180 service.AddressProtocol = address_protocol;
181  
182 ServiceBrowseEventArgs args = new ServiceBrowseEventArgs(
183 service, (flags & ServiceFlags.MoreComing) != 0);
184  
185 if((flags & ServiceFlags.Add) != 0) {
186 lock (service_table) {
2 office 187 if (service_table.ContainsKey (name)) {
188 service_table[name] = service;
1 office 189 } else {
2 office 190 service_table.Add(name, service);
1 office 191 }
192 }
193  
194 ServiceBrowseEventHandler handler = ServiceAdded;
195 if(handler != null) {
196 handler(this, args);
197 }
198 } else {
199 lock (service_table) {
2 office 200 if (service_table.ContainsKey (name)) {
201 service_table.Remove (name);
1 office 202 }
203 }
204  
205 ServiceBrowseEventHandler handler = ServiceRemoved;
206 if(handler != null) {
207 handler(this, args);
208 }
209 }
210 }
211 }
212 }