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