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