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