]> git.meshlink.io Git - catta/blob - avahi-sharp/ServiceResolver.cs
lose the dep on avahi-glib, and run the avahi loop in a thread
[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, IntPtr userdata);
35
36     public class ServiceResolver : IDisposable
37     {
38         private IntPtr handle;
39         private ServiceInfo currentInfo;
40         private Client client;
41         private int iface;
42         private Protocol proto;
43         private string name;
44         private string type;
45         private string domain;
46         private Protocol aproto;
47         private ServiceResolverCallback cb;
48
49         private ArrayList foundListeners = new ArrayList ();
50         private ArrayList timeoutListeners = new ArrayList ();
51         
52         [DllImport ("avahi-client")]
53         private static extern IntPtr avahi_service_resolver_new (IntPtr client, int iface, Protocol proto,
54                                                                  IntPtr name, IntPtr type, IntPtr domain,
55                                                                  Protocol aproto, ServiceResolverCallback cb,
56                                                                  IntPtr userdata);
57
58         [DllImport ("avahi-common")]
59         private static extern IntPtr avahi_string_list_get_next (IntPtr list);
60
61         [DllImport ("avahi-common")]
62         private static extern IntPtr avahi_string_list_get_text (IntPtr list);
63
64         [DllImport ("avahi-common")]
65         private static extern int avahi_string_list_get_size (IntPtr list);
66
67         [DllImport ("avahi-client")]
68         private static extern void avahi_service_resolver_free (IntPtr handle);
69
70         public event ServiceInfoHandler Found
71         {
72             add {
73                 foundListeners.Add (value);
74                 Start ();
75             }
76             remove {
77                 foundListeners.Remove (value);
78                 Stop (false);
79             }
80         }
81         
82         public event EventHandler Timeout
83         {
84             add {
85                 timeoutListeners.Add (value);
86                 Start ();
87             }
88             remove {
89                 timeoutListeners.Remove (value);
90                 Stop (false);
91             }
92         }
93
94         public ServiceInfo Service
95         {
96             get { return currentInfo; }
97         }
98
99         public ServiceResolver (Client client, string name, string type, string domain) : this (client, -1,
100                                                                                                 Protocol.Unspecified,
101                                                                                                 name, type, domain,
102                                                                                                 Protocol.Unspecified)
103         {
104         }
105
106         public ServiceResolver (Client client, ServiceInfo service) : this (client, service.NetworkInterface,
107                                                                             service.Protocol, service.Name,
108                                                                             service.ServiceType, service.Domain,
109                                                                             Protocol.Unspecified)
110         {
111         }
112         
113         public ServiceResolver (Client client, int iface, Protocol proto, string name,
114                                 string type, string domain, Protocol aproto)
115         {
116             this.client = client;
117             this.iface = iface;
118             this.proto = proto;
119             this.name = name;
120             this.type = type;
121             this.domain = domain;
122             this.aproto = aproto;
123             cb = OnServiceResolverCallback;
124         }
125
126         ~ServiceResolver ()
127         {
128             Dispose ();
129         }
130
131         public void Dispose ()
132         {
133             Stop (true);
134         }
135
136         private void Start ()
137         {
138             if (client.Handle == IntPtr.Zero || handle != IntPtr.Zero ||
139                 (foundListeners.Count == 0 && timeoutListeners.Count == 0))
140                 return;
141
142             IntPtr namePtr = Utility.StringToPtr (name);
143             IntPtr typePtr = Utility.StringToPtr (type);
144             IntPtr domainPtr = Utility.StringToPtr (domain);
145
146             lock (client) {
147                 handle = avahi_service_resolver_new (client.Handle, iface, proto, namePtr, typePtr, domainPtr,
148                                                      aproto, cb, IntPtr.Zero);
149             }
150             
151             Utility.Free (namePtr);
152             Utility.Free (typePtr);
153             Utility.Free (domainPtr);
154         }
155
156         private void Stop (bool force)
157         {
158             if (client.Handle != IntPtr.Zero && handle != IntPtr.Zero &&
159                 (force || (foundListeners.Count == 0 && timeoutListeners.Count == 0))) {
160
161                 lock (client) {
162                     avahi_service_resolver_free (handle);
163                     handle = IntPtr.Zero;
164                 }
165             }
166         }
167
168         private void OnServiceResolverCallback (IntPtr resolver, int iface, Protocol proto,
169                                                 ResolverEvent revent, IntPtr name, IntPtr type,
170                                                 IntPtr domain, IntPtr host, IntPtr address,
171                                                 UInt16 port, IntPtr txt, IntPtr userdata)
172         {
173             ServiceInfo info;
174             info.NetworkInterface = iface;
175             info.Protocol = proto;
176             info.Domain = Utility.PtrToString (domain);
177             info.ServiceType = Utility.PtrToString (type);
178             info.Name = Utility.PtrToString (name);
179             info.HostName = Utility.PtrToString (host);
180             info.Address = Utility.PtrToAddress (address);
181             info.Port = port;
182
183             ArrayList txtlist = new ArrayList ();
184             for (IntPtr l = txt; l != IntPtr.Zero; l = avahi_string_list_get_next (l)) {
185                 IntPtr buf = avahi_string_list_get_text (l);
186                 int len = avahi_string_list_get_size (l);
187
188                 byte[] txtbuf = new byte[len];
189                 Marshal.Copy (buf, txtbuf, 0, len);
190                 txtlist.Add (txtbuf);
191             }
192
193             info.Text = (byte[][]) txtlist.ToArray (typeof (byte[]));
194             
195             if (revent == ResolverEvent.Found) {
196                 currentInfo = info;
197
198                 foreach (ServiceInfoHandler handler in foundListeners)
199                     handler (this, info);
200             } else {
201                 currentInfo = ServiceInfo.Zero;
202                 
203                 foreach (EventHandler handler in timeoutListeners)
204                     handler (this, new EventArgs ());
205             }
206         }
207     }
208 }