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