]> git.meshlink.io Git - catta/blob - avahi-sharp/Client.cs
8ec6616d4403b956201f9d91c38884631540e5e2
[catta] / avahi-sharp / Client.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
23 using System;
24 using System.Threading;
25 using System.Collections;
26 using System.Runtime.InteropServices;
27 using Mono.Unix;
28 using Mono.Unix.Native;
29
30 using Stdlib = Mono.Unix.Native.Stdlib;
31
32 namespace Avahi
33 {
34     internal enum ResolverEvent {
35         Found,
36         Failure
37     }
38     
39     internal enum BrowserEvent {
40         Added,
41         Removed,
42         CacheExhausted,
43         AllForNow,
44         Failure
45     }
46
47     internal delegate int PollCallback (IntPtr ufds, uint nfds, int timeout);
48     internal delegate void ClientCallback (IntPtr client, ClientState state, IntPtr userData);
49
50     public delegate void ClientStateHandler (object o, ClientStateArgs state);
51
52     public class ClientStateArgs : EventArgs
53     {
54         private ClientState state;
55
56         public ClientState State
57         {
58             get { return state; }
59         }
60
61         public ClientStateArgs (ClientState state)
62         {
63             this.state = state;
64         }
65     }
66     
67     public enum Protocol {
68         Unspecified = -1,
69         IPv4 = 0,
70         IPv6 = 1
71     }
72
73     internal enum ServerState {
74         Invalid,
75         Registering,
76         Running,
77         Collision
78     }
79     
80     public enum ClientState {
81         Registering = ServerState.Registering,
82         Running = ServerState.Running,
83         Collision = ServerState.Collision,
84         Failure = 100,
85         Connecting = 101
86     }
87
88     [Flags]
89     public enum LookupFlags {
90         None = 0,
91         UseWideArea = 1,
92         UseMulticast = 2,
93         NoTxt = 4,
94         NoAddress = 8
95     }
96
97     [Flags]
98     public enum LookupResultFlags {
99         None = 0,
100         Cached = 1,
101         WideArea = 2,
102         Multicast = 4,
103         Local = 8,
104         OurOwn = 16,
105     }
106
107     [Flags]
108     public enum ClientFlags {
109         None = 0,
110         IgnoreUserConfig = 1,
111         NoFail = 2
112     }
113     
114     public class Client : IDisposable
115     {
116         private IntPtr handle;
117         private ClientCallback cb;
118         private PollCallback pollcb;
119         private IntPtr spoll;
120
121         private Thread thread;
122
123         [DllImport ("avahi-client")]
124         private static extern IntPtr avahi_client_new (IntPtr poll, ClientFlags flags, ClientCallback handler,
125                                                        IntPtr userData, out int error);
126
127         [DllImport ("avahi-client")]
128         private static extern void avahi_client_free (IntPtr handle);
129
130         [DllImport ("avahi-client")]
131         private static extern IntPtr avahi_client_get_version_string (IntPtr handle);
132
133         [DllImport ("avahi-client")]
134         private static extern IntPtr avahi_client_get_host_name (IntPtr handle);
135
136         [DllImport ("avahi-client")]
137         private static extern IntPtr avahi_client_get_domain_name (IntPtr handle);
138
139         [DllImport ("avahi-client")]
140         private static extern IntPtr avahi_client_get_host_name_fqdn (IntPtr handle);
141
142         [DllImport ("avahi-client")]
143         private static extern ClientState avahi_client_get_state (IntPtr handle);
144
145         [DllImport ("avahi-client")]
146         private static extern int avahi_client_errno (IntPtr handle);
147         
148         [DllImport ("avahi-common")]
149         private static extern IntPtr avahi_simple_poll_new ();
150
151         [DllImport ("avahi-common")]
152         private static extern IntPtr avahi_simple_poll_get (IntPtr spoll);
153
154         [DllImport ("avahi-common")]
155         private static extern void avahi_simple_poll_free (IntPtr spoll);
156
157         [DllImport ("avahi-common")]
158         private static extern int avahi_simple_poll_loop (IntPtr spoll);
159
160         [DllImport ("avahi-common")]
161         private static extern void avahi_simple_poll_set_func (IntPtr spoll, PollCallback cb);
162
163         [DllImport ("avahi-common")]
164         private static extern void avahi_simple_poll_quit (IntPtr spoll);
165
166         [DllImport ("avahi-client")]
167         private static extern uint avahi_client_get_local_service_cookie (IntPtr client);
168
169         [DllImport ("avahi-common")]
170         private static extern int avahi_service_name_join (IntPtr buf, int len, byte[] name, byte[] type,
171                                                            byte[] domain);
172
173         [DllImport ("avahi-common")]
174         private static extern int avahi_service_name_split (byte[] service, IntPtr name, int name_len,
175                                                             IntPtr type, int type_len,
176                                                             IntPtr domain, int domain_len);
177
178
179         [DllImport ("libc")]
180         private static extern int poll(IntPtr ufds, uint nfds, int timeout);
181
182         public event ClientStateHandler StateChanged;
183
184         internal IntPtr Handle
185         {
186             get { return handle; }
187         }
188         
189         public string Version
190         {
191             get {
192                 lock (this) {
193                     return Utility.PtrToString (avahi_client_get_version_string (handle));
194                 }
195             }
196         }
197
198         public string HostName
199         {
200             get {
201                 lock (this) {
202                     return Utility.PtrToString (avahi_client_get_host_name (handle));
203                 }
204             }
205         }
206
207         public string DomainName
208         {
209             get {
210                 lock (this) {
211                     return Utility.PtrToString (avahi_client_get_domain_name (handle));
212                 }
213             }
214         }
215
216         public string HostNameFqdn
217         {
218             get {
219                 lock (this) {
220                     return Utility.PtrToString (avahi_client_get_host_name_fqdn (handle));
221                 }
222             }
223         }
224
225         public ClientState State
226         {
227             get {
228                 lock (this) {
229                     return (ClientState) avahi_client_get_state (handle);
230                 }
231             }
232         }
233
234         public uint LocalServiceCookie
235         {
236             get {
237                 lock (this) {
238                     return avahi_client_get_local_service_cookie (handle);
239                 }
240             }
241         }
242
243         internal ErrorCode LastError
244         {
245             get {
246                 lock (this) {
247                     return (ErrorCode) avahi_client_errno (handle);
248                 }
249             }
250         }
251
252         public Client (ClientFlags flags)
253         {
254             spoll = avahi_simple_poll_new ();
255
256             pollcb = OnPollCallback;
257             avahi_simple_poll_set_func (spoll, pollcb);
258             IntPtr poll = avahi_simple_poll_get (spoll);
259             cb = OnClientCallback;
260
261             int error;
262             handle = avahi_client_new (poll, flags, cb, IntPtr.Zero, out error);
263             if (error != 0)
264                 throw new ClientException (error);
265
266             thread = new Thread (PollLoop);
267             thread.IsBackground = true;
268             thread.Start ();
269         }
270
271         public Client () : this (ClientFlags.None) {
272         }
273
274         ~Client ()
275         {
276             Dispose ();
277         }
278
279         public void Dispose ()
280         {
281             if (handle != IntPtr.Zero) {
282                 avahi_client_free (handle);
283                 avahi_simple_poll_quit (spoll);
284                 avahi_simple_poll_free (spoll);
285                 handle = IntPtr.Zero;
286             }
287         }
288
289         public static string JoinServiceName (string name, string type, string domain)
290         {
291             int len = 4 * (name.Length + type.Length + domain.Length) + 4;
292             IntPtr buf = Stdlib.malloc ((ulong) len);
293
294             int ret = avahi_service_name_join (buf, len,
295                                                Utility.StringToBytes (name),
296                                                Utility.StringToBytes (type),
297                                                Utility.StringToBytes (domain));
298
299             if (ret < 0) {
300                 Utility.Free (buf);
301                 return null; // FIXME, should throw exception
302             }
303
304             string service = Utility.PtrToString (buf);
305             Utility.Free (buf);
306
307             return service;
308         }
309
310         public static void SplitServiceName (string service, out string name, out string type, out string domain)
311         {
312             int len = 1024;
313
314             IntPtr namePtr = Stdlib.malloc ((ulong) len);
315             IntPtr typePtr = Stdlib.malloc ((ulong) len);
316             IntPtr domainPtr = Stdlib.malloc ((ulong) len);
317             
318             int ret = avahi_service_name_split (Utility.StringToBytes (service), namePtr, len, typePtr, len,
319                                                 domainPtr, len);
320
321             if (ret < 0) {
322                 Utility.Free (namePtr);
323                 Utility.Free (typePtr);
324                 Utility.Free (domainPtr);
325                 
326                 name = null;
327                 type = null;
328                 domain = null;
329                 return;
330             }
331
332             name = Utility.PtrToString (namePtr);
333             type = Utility.PtrToString (typePtr);
334             domain = Utility.PtrToString (domainPtr);
335
336             Utility.Free (namePtr);
337             Utility.Free (typePtr);
338             Utility.Free (domainPtr);
339         }
340
341         internal void ThrowError ()
342         {
343             ErrorCode error = LastError;
344
345             if (error != ErrorCode.Ok)
346                 throw new ClientException (error);
347         }
348         
349         private void OnClientCallback (IntPtr client, ClientState state, IntPtr userData)
350         {
351             if (StateChanged != null)
352                 StateChanged (this, new ClientStateArgs (state));
353         }
354
355         private int OnPollCallback (IntPtr ufds, uint nfds, int timeout) {
356             Monitor.Exit (this);
357             int result = poll (ufds, nfds, timeout);
358             Monitor.Enter (this);
359             return result;
360         }
361
362         private void PollLoop () {
363             try {
364                 lock (this) {
365                     avahi_simple_poll_loop (spoll);
366                 }
367             } catch (Exception e) {
368                 Console.Error.WriteLine ("Error in avahi-sharp event loop: " + e);
369             }
370         }
371     }
372 }