]> git.meshlink.io Git - catta/blob - avahi-sharp/ServiceResolver.cs
Complete AVAHI_LOOKUP_NO_ADDRESS fix
[catta] / avahi-sharp / ServiceResolver.cs
1 /* $Id$ */
2
3 /***
4   This file is part of avahi.
5
6   avahi is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as
8   published by the Free Software Foundation; either version 2.1 of the
9   License, or (at your option) any later version.
10
11   avahi is distributed in the hope that it will be useful, but WITHOUT
12   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13   or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
14   Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with avahi; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 using System;
23 using System.Collections;
24 using System.Net;
25 using System.Runtime.InteropServices;
26 using Mono.Unix;
27
28 namespace Avahi
29 {
30
31     internal delegate void ServiceResolverCallback (IntPtr resolver, int iface, Protocol proto,
32                                                     ResolverEvent revent, IntPtr name, IntPtr type,
33                                                     IntPtr domain, IntPtr host, IntPtr address,
34                                                     UInt16 port, IntPtr txt, LookupResultFlags flags,
35                                                     IntPtr userdata);
36
37     public class ServiceResolver : ResolverBase, IDisposable
38     {
39         private IntPtr handle;
40         private ServiceInfo currentInfo;
41         private Client client;
42         private int iface;
43         private Protocol proto;
44         private string name;
45         private string type;
46         private string domain;
47         private Protocol aproto;
48         private LookupFlags flags;
49         private ServiceResolverCallback cb;
50
51         private ArrayList foundListeners = new ArrayList ();
52         private ArrayList timeoutListeners = new ArrayList ();
53         
54         [DllImport ("avahi-client")]
55         private static extern IntPtr avahi_service_resolver_new (IntPtr client, int iface, Protocol proto,
56                                                                  IntPtr name, IntPtr type, IntPtr domain,
57                                                                  Protocol aproto, LookupFlags flags,
58                                                                  ServiceResolverCallback cb,
59                                                                  IntPtr userdata);
60
61         [DllImport ("avahi-common")]
62         private static extern IntPtr avahi_string_list_get_next (IntPtr list);
63
64         [DllImport ("avahi-common")]
65         private static extern IntPtr avahi_string_list_get_text (IntPtr list);
66
67         [DllImport ("avahi-common")]
68         private static extern int avahi_string_list_get_size (IntPtr list);
69
70         [DllImport ("avahi-client")]
71         private static extern void avahi_service_resolver_free (IntPtr handle);
72
73         public event ServiceInfoHandler Found
74         {
75             add {
76                 foundListeners.Add (value);
77                 Start ();
78             }
79             remove {
80                 foundListeners.Remove (value);
81                 Stop (false);
82             }
83         }
84         
85         public event EventHandler Timeout
86         {
87             add {
88                 timeoutListeners.Add (value);
89                 Start ();
90             }
91             remove {
92                 timeoutListeners.Remove (value);
93                 Stop (false);
94             }
95         }
96
97         public ServiceInfo Service
98         {
99             get { return currentInfo; }
100         }
101
102         public ServiceResolver (Client client, string name, string type, string domain) : this (client, -1,
103                                                                                                 Protocol.Unspecified,
104                                                                                                 name, type, domain,
105                                                                                                 Protocol.Unspecified,
106                                                                                                 LookupFlags.None)
107         {
108         }
109
110         public ServiceResolver (Client client, ServiceInfo service) : this (client, service.NetworkInterface,
111                                                                             service.Protocol, service.Name,
112                                                                             service.ServiceType, service.Domain,
113                                                                             Protocol.Unspecified,
114                                                                             GetLookupFlags (service.Flags))
115         {
116         }
117         
118         public ServiceResolver (Client client, int iface, Protocol proto, string name,
119                                 string type, string domain, Protocol aproto, LookupFlags flags)
120         {
121             this.client = client;
122             this.iface = iface;
123             this.proto = proto;
124             this.name = name;
125             this.type = type;
126             this.domain = domain;
127             this.aproto = aproto;
128             this.flags = flags;
129             cb = OnServiceResolverCallback;
130         }
131
132         ~ServiceResolver ()
133         {
134             Dispose ();
135         }
136
137         public void Dispose ()
138         {
139             Stop (true);
140         }
141
142         private void Start ()
143         {
144             if (client.Handle == IntPtr.Zero || handle != IntPtr.Zero ||
145                 (foundListeners.Count == 0 && timeoutListeners.Count == 0))
146                 return;
147
148             IntPtr namePtr = Utility.StringToPtr (name);
149             IntPtr typePtr = Utility.StringToPtr (type);
150             IntPtr domainPtr = Utility.StringToPtr (domain);
151
152             lock (client) {
153                 handle = avahi_service_resolver_new (client.Handle, iface, proto, namePtr, typePtr, domainPtr,
154                                                      aproto, flags, cb, IntPtr.Zero);
155             }
156             
157             Utility.Free (namePtr);
158             Utility.Free (typePtr);
159             Utility.Free (domainPtr);
160         }
161
162         private void Stop (bool force)
163         {
164             if (client.Handle != IntPtr.Zero && handle != IntPtr.Zero &&
165                 (force || (foundListeners.Count == 0 && timeoutListeners.Count == 0))) {
166
167                 lock (client) {
168                     avahi_service_resolver_free (handle);
169                     handle = IntPtr.Zero;
170                 }
171             }
172         }
173
174         private void OnServiceResolverCallback (IntPtr resolver, int iface, Protocol proto,
175                                                 ResolverEvent revent, IntPtr name, IntPtr type,
176                                                 IntPtr domain, IntPtr host, IntPtr address,
177                                                 UInt16 port, IntPtr txt, LookupResultFlags flags,
178                                                 IntPtr userdata)
179         {
180             ServiceInfo info;
181             info.NetworkInterface = iface;
182             info.Protocol = proto;
183             info.Domain = Utility.PtrToString (domain);
184             info.ServiceType = Utility.PtrToString (type);
185             info.Name = Utility.PtrToString (name);
186             info.HostName = Utility.PtrToString (host);
187             info.Address = Utility.PtrToAddress (address);
188             info.Port = port;
189
190             ArrayList txtlist = new ArrayList ();
191             for (IntPtr l = txt; l != IntPtr.Zero; l = avahi_string_list_get_next (l)) {
192                 IntPtr buf = avahi_string_list_get_text (l);
193                 int len = avahi_string_list_get_size (l);
194
195                 byte[] txtbuf = new byte[len];
196                 Marshal.Copy (buf, txtbuf, 0, len);
197                 txtlist.Add (txtbuf);
198             }
199
200             info.Text = (byte[][]) txtlist.ToArray (typeof (byte[]));
201             info.Flags = flags;
202
203             switch (revent) {
204             case ResolverEvent.Found:
205                 currentInfo = info;
206
207                 foreach (ServiceInfoHandler handler in foundListeners)
208                     handler (this, info);
209                 break;
210             case ResolverEvent.Timeout:
211                 currentInfo = ServiceInfo.Zero;
212                 
213                 foreach (EventHandler handler in timeoutListeners)
214                     handler (this, new EventArgs ());
215                 break;
216             default:
217                 EmitResolverEvent (revent);
218                 break;
219             }
220         }
221
222         private static LookupFlags GetLookupFlags (LookupResultFlags rflags) {
223             LookupFlags ret = LookupFlags.None;
224
225             if ((rflags & LookupResultFlags.Multicast) > 0)
226                 ret |= LookupFlags.UseMulticast;
227             if ((rflags & LookupResultFlags.WideArea) > 0)
228                 ret |= LookupFlags.UseWideArea;
229
230             return ret;
231         }
232     }
233 }