]> git.meshlink.io Git - catta/blob - avahi-sharp/ServiceResolver.cs
a32efca8b795186bf19dd429e7dcc97944823680
[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 System.Text;
27 using Mono.Unix;
28
29 namespace Avahi
30 {
31
32     internal delegate void ServiceResolverCallback (IntPtr resolver, int iface, Protocol proto,
33                                                     ResolverEvent revent, IntPtr name, IntPtr type,
34                                                     IntPtr domain, IntPtr host, IntPtr address,
35                                                     UInt16 port, IntPtr txt, LookupResultFlags flags,
36                                                     IntPtr userdata);
37
38     public class ServiceResolver : ResolverBase, IDisposable
39     {
40         private IntPtr handle;
41         private ServiceInfo currentInfo;
42         private Client client;
43         private int iface;
44         private Protocol proto;
45         private string name;
46         private string type;
47         private string domain;
48         private Protocol aproto;
49         private LookupFlags flags;
50         private ServiceResolverCallback cb;
51
52         private ArrayList foundListeners = new ArrayList ();
53         private ArrayList timeoutListeners = new ArrayList ();
54         
55         [DllImport ("avahi-client")]
56         private static extern IntPtr avahi_service_resolver_new (IntPtr client, int iface, Protocol proto,
57                                                                  byte[] name, byte[] type, byte[] domain,
58                                                                  Protocol aproto, LookupFlags flags,
59                                                                  ServiceResolverCallback cb,
60                                                                  IntPtr userdata);
61
62         [DllImport ("avahi-common")]
63         private static extern IntPtr avahi_string_list_get_next (IntPtr list);
64
65         [DllImport ("avahi-common")]
66         private static extern IntPtr avahi_string_list_get_text (IntPtr list);
67
68         [DllImport ("avahi-common")]
69         private static extern int avahi_string_list_get_size (IntPtr list);
70
71         [DllImport ("avahi-client")]
72         private static extern void avahi_service_resolver_free (IntPtr handle);
73
74         public event ServiceInfoHandler Found
75         {
76             add {
77                 foundListeners.Add (value);
78                 Start ();
79             }
80             remove {
81                 foundListeners.Remove (value);
82                 Stop (false);
83             }
84         }
85         
86         public event EventHandler Timeout
87         {
88             add {
89                 timeoutListeners.Add (value);
90                 Start ();
91             }
92             remove {
93                 timeoutListeners.Remove (value);
94                 Stop (false);
95             }
96         }
97
98         public ServiceInfo Service
99         {
100             get { return currentInfo; }
101         }
102
103         public ServiceResolver (Client client, string name, string type, string domain) : this (client, -1,
104                                                                                                 Protocol.Unspecified,
105                                                                                                 name, type, domain,
106                                                                                                 Protocol.Unspecified,
107                                                                                                 LookupFlags.None)
108         {
109         }
110
111         public ServiceResolver (Client client, ServiceInfo service) : this (client, service.NetworkInterface,
112                                                                             service.Protocol, service.Name,
113                                                                             service.ServiceType, service.Domain,
114                                                                             Protocol.Unspecified,
115                                                                             GetLookupFlags (service.Flags))
116         {
117         }
118         
119         public ServiceResolver (Client client, int iface, Protocol proto, string name,
120                                 string type, string domain, Protocol aproto, LookupFlags flags)
121         {
122             this.client = client;
123             this.iface = iface;
124             this.proto = proto;
125             this.name = name;
126             this.type = type;
127             this.domain = domain;
128             this.aproto = aproto;
129             this.flags = flags;
130             cb = OnServiceResolverCallback;
131         }
132
133         ~ServiceResolver ()
134         {
135             Dispose ();
136         }
137
138         public void Dispose ()
139         {
140             Stop (true);
141         }
142
143         private void Start ()
144         {
145             if (client.Handle == IntPtr.Zero || handle != IntPtr.Zero ||
146                 (foundListeners.Count == 0 && timeoutListeners.Count == 0))
147                 return;
148
149             lock (client) {
150                 handle = avahi_service_resolver_new (client.Handle, iface, proto,
151                                                      Utility.StringToBytes (name), Utility.StringToBytes (type),
152                                                      Utility.StringToBytes (domain), aproto, flags, cb, IntPtr.Zero);
153
154                 if (handle == IntPtr.Zero)
155                     client.ThrowError ();
156             }
157         }
158
159         private void Stop (bool force)
160         {
161             if (client.Handle != IntPtr.Zero && handle != IntPtr.Zero &&
162                 (force || (foundListeners.Count == 0 && timeoutListeners.Count == 0))) {
163
164                 lock (client) {
165                     avahi_service_resolver_free (handle);
166                     handle = IntPtr.Zero;
167                 }
168             }
169         }
170
171         private void OnServiceResolverCallback (IntPtr resolver, int iface, Protocol proto,
172                                                 ResolverEvent revent, IntPtr name, IntPtr type,
173                                                 IntPtr domain, IntPtr host, IntPtr address,
174                                                 UInt16 port, IntPtr txt, LookupResultFlags flags,
175                                                 IntPtr userdata)
176         {
177             ServiceInfo info;
178             info.NetworkInterface = iface;
179             info.Protocol = proto;
180             info.Domain = Utility.PtrToString (domain);
181             info.ServiceType = Utility.PtrToString (type);
182             info.Name = Utility.PtrToString (name);
183             info.HostName = Utility.PtrToString (host);
184             info.Address = Utility.PtrToAddress (address);
185             info.Port = port;
186
187             if (proto == Protocol.IPv6)
188               info.Address.ScopeId = iface;
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, new ServiceInfoArgs (info));
209                 break;
210             case ResolverEvent.Failure:
211                 EmitFailure (client.LastError);
212                 break;
213             }
214         }
215
216         private static LookupFlags GetLookupFlags (LookupResultFlags rflags) {
217             LookupFlags ret = LookupFlags.None;
218
219             if ((rflags & LookupResultFlags.Multicast) > 0)
220                 ret |= LookupFlags.UseMulticast;
221             if ((rflags & LookupResultFlags.WideArea) > 0)
222                 ret |= LookupFlags.UseWideArea;
223
224             return ret;
225         }
226     }
227 }